Merge branch 'master' into vehicles
commit
6deef7d0f3
|
@ -774,6 +774,11 @@ namespace OpenSim.Client.MXP.ClientStack
|
||||||
get { return m_sessionID.CRC(); }
|
get { return m_sessionID.CRC(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IPEndPoint RemoteEndPoint
|
||||||
|
{
|
||||||
|
get { return Session.RemoteEndPoint; }
|
||||||
|
}
|
||||||
|
|
||||||
public void SetDebugPacketLevel(int newDebug)
|
public void SetDebugPacketLevel(int newDebug)
|
||||||
{
|
{
|
||||||
//m_debugLevel = newDebug;
|
//m_debugLevel = newDebug;
|
||||||
|
@ -798,9 +803,9 @@ namespace OpenSim.Client.MXP.ClientStack
|
||||||
OnConnectionClosed(this);
|
OnConnectionClosed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close(bool ShutdownCircuit)
|
public void Close()
|
||||||
{
|
{
|
||||||
m_log.Info("[MXP ClientStack] Close Called with SC=" + ShutdownCircuit);
|
m_log.Info("[MXP ClientStack] Close Called");
|
||||||
|
|
||||||
// Tell the client to go
|
// Tell the client to go
|
||||||
SendLogoutPacket();
|
SendLogoutPacket();
|
||||||
|
@ -815,7 +820,7 @@ namespace OpenSim.Client.MXP.ClientStack
|
||||||
|
|
||||||
public void Kick(string message)
|
public void Kick(string message)
|
||||||
{
|
{
|
||||||
Close(false);
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
|
@ -1448,7 +1453,7 @@ namespace OpenSim.Client.MXP.ClientStack
|
||||||
|
|
||||||
public void Terminate()
|
public void Terminate()
|
||||||
{
|
{
|
||||||
Close(false);
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendSetFollowCamProperties(UUID objectID, SortedDictionary<int, float> parameters)
|
public void SendSetFollowCamProperties(UUID objectID, SortedDictionary<int, float> parameters)
|
||||||
|
@ -1615,12 +1620,12 @@ namespace OpenSim.Client.MXP.ClientStack
|
||||||
public void Disconnect(string reason)
|
public void Disconnect(string reason)
|
||||||
{
|
{
|
||||||
Kick(reason);
|
Kick(reason);
|
||||||
Close(true);
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disconnect()
|
public void Disconnect()
|
||||||
{
|
{
|
||||||
Close(true);
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -339,12 +339,6 @@ namespace OpenSim.Client.MXP.PacketHandler
|
||||||
m_clients.Add(client);
|
m_clients.Add(client);
|
||||||
m_log.Debug("[MXP ClientStack]: Created ClientView.");
|
m_log.Debug("[MXP ClientStack]: Created ClientView.");
|
||||||
|
|
||||||
|
|
||||||
m_log.Debug("[MXP ClientStack]: Adding ClientView to Scene...");
|
|
||||||
scene.ClientManager.Add(client.CircuitCode, client);
|
|
||||||
m_log.Debug("[MXP ClientStack]: Added ClientView to Scene.");
|
|
||||||
|
|
||||||
|
|
||||||
client.MXPSendSynchronizationBegin(m_scenes[new UUID(joinRequestMessage.BubbleId)].SceneContents.GetTotalObjectsCount());
|
client.MXPSendSynchronizationBegin(m_scenes[new UUID(joinRequestMessage.BubbleId)].SceneContents.GetTotalObjectsCount());
|
||||||
|
|
||||||
m_log.Debug("[MXP ClientStack]: Starting ClientView...");
|
m_log.Debug("[MXP ClientStack]: Starting ClientView...");
|
||||||
|
|
|
@ -207,6 +207,11 @@ namespace OpenSim.Client.VWoHTTP.ClientStack
|
||||||
get { throw new System.NotImplementedException(); }
|
get { throw new System.NotImplementedException(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IPEndPoint RemoteEndPoint
|
||||||
|
{
|
||||||
|
get { throw new System.NotImplementedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
public event GenericMessage OnGenericMessage = delegate { };
|
public event GenericMessage OnGenericMessage = delegate { };
|
||||||
public event ImprovedInstantMessage OnInstantMessage = delegate { };
|
public event ImprovedInstantMessage OnInstantMessage = delegate { };
|
||||||
public event ChatMessage OnChatFromClient = delegate { };
|
public event ChatMessage OnChatFromClient = delegate { };
|
||||||
|
@ -415,7 +420,7 @@ namespace OpenSim.Client.VWoHTTP.ClientStack
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close(bool ShutdownCircuit)
|
public void Close()
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,8 +151,11 @@ namespace OpenSim.Data.MySQL
|
||||||
|
|
||||||
DataTable schemaTable = result.GetSchemaTable();
|
DataTable schemaTable = result.GetSchemaTable();
|
||||||
foreach (DataRow row in schemaTable.Rows)
|
foreach (DataRow row in schemaTable.Rows)
|
||||||
|
{
|
||||||
|
if (row["ColumnName"] != null)
|
||||||
m_ColumnNames.Add(row["ColumnName"].ToString());
|
m_ColumnNames.Add(row["ColumnName"].ToString());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (string s in m_ColumnNames)
|
foreach (string s in m_ColumnNames)
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,193 +28,195 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using log4net;
|
using System.Net;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenMetaverse.Packets;
|
using OpenMetaverse.Packets;
|
||||||
|
|
||||||
namespace OpenSim.Framework
|
namespace OpenSim.Framework
|
||||||
{
|
{
|
||||||
public delegate void ForEachClientDelegate(IClientAPI client);
|
/// <summary>
|
||||||
|
/// Maps from client AgentID and RemoteEndPoint values to IClientAPI
|
||||||
|
/// references for all of the connected clients
|
||||||
|
/// </summary>
|
||||||
public class ClientManager
|
public class ClientManager
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
/// <summary>A dictionary mapping from <seealso cref="UUID"/>
|
||||||
|
/// to <seealso cref="IClientAPI"/> references</summary>
|
||||||
|
private Dictionary<UUID, IClientAPI> m_dict1;
|
||||||
|
/// <summary>A dictionary mapping from <seealso cref="IPEndPoint"/>
|
||||||
|
/// to <seealso cref="IClientAPI"/> references</summary>
|
||||||
|
private Dictionary<IPEndPoint, IClientAPI> m_dict2;
|
||||||
|
/// <summary>An immutable collection of <seealso cref="IClientAPI"/>
|
||||||
|
/// references</summary>
|
||||||
|
private IClientAPI[] m_array;
|
||||||
|
/// <summary>Synchronization object for writing to the collections</summary>
|
||||||
|
private object m_syncRoot = new object();
|
||||||
|
|
||||||
private Dictionary<uint, IClientAPI> m_clients;
|
/// <summary>Number of clients in the collection</summary>
|
||||||
|
public int Count { get { return m_dict1.Count; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default constructor
|
||||||
|
/// </summary>
|
||||||
public ClientManager()
|
public ClientManager()
|
||||||
{
|
{
|
||||||
m_clients = new Dictionary<uint, IClientAPI>();
|
m_dict1 = new Dictionary<UUID, IClientAPI>();
|
||||||
|
m_dict2 = new Dictionary<IPEndPoint, IClientAPI>();
|
||||||
|
m_array = new IClientAPI[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ForEachClient(ForEachClientDelegate whatToDo)
|
/// <summary>
|
||||||
|
/// Add a client reference to the collection if it does not already
|
||||||
|
/// exist
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">Reference to the client object</param>
|
||||||
|
/// <returns>True if the client reference was successfully added,
|
||||||
|
/// otherwise false if the given key already existed in the collection</returns>
|
||||||
|
public bool Add(IClientAPI value)
|
||||||
{
|
{
|
||||||
IClientAPI[] LocalClients;
|
lock (m_syncRoot)
|
||||||
lock (m_clients)
|
|
||||||
{
|
{
|
||||||
LocalClients = new IClientAPI[m_clients.Count];
|
if (m_dict1.ContainsKey(value.AgentId) || m_dict2.ContainsKey(value.RemoteEndPoint))
|
||||||
m_clients.Values.CopyTo(LocalClients, 0);
|
return false;
|
||||||
|
|
||||||
|
m_dict1[value.AgentId] = value;
|
||||||
|
m_dict2[value.RemoteEndPoint] = value;
|
||||||
|
|
||||||
|
IClientAPI[] oldArray = m_array;
|
||||||
|
int oldLength = oldArray.Length;
|
||||||
|
|
||||||
|
IClientAPI[] newArray = new IClientAPI[oldLength + 1];
|
||||||
|
for (int i = 0; i < oldLength; i++)
|
||||||
|
newArray[i] = oldArray[i];
|
||||||
|
newArray[oldLength] = value;
|
||||||
|
|
||||||
|
m_array = newArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < LocalClients.Length; i++)
|
return true;
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
whatToDo(LocalClients[i]);
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove a client from the collection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">UUID of the client to remove</param>
|
||||||
|
/// <returns>True if a client was removed, or false if the given UUID
|
||||||
|
/// was not present in the collection</returns>
|
||||||
|
public bool Remove(UUID key)
|
||||||
{
|
{
|
||||||
m_log.Warn("[CLIENT]: Unable to do ForEachClient for one of the clients" + "\n Reason: " + e.ToString());
|
lock (m_syncRoot)
|
||||||
|
{
|
||||||
|
IClientAPI value;
|
||||||
|
if (m_dict1.TryGetValue(key, out value))
|
||||||
|
{
|
||||||
|
m_dict1.Remove(key);
|
||||||
|
m_dict2.Remove(value.RemoteEndPoint);
|
||||||
|
|
||||||
|
IClientAPI[] oldArray = m_array;
|
||||||
|
int oldLength = oldArray.Length;
|
||||||
|
|
||||||
|
IClientAPI[] newArray = new IClientAPI[oldLength - 1];
|
||||||
|
int j = 0;
|
||||||
|
for (int i = 0; i < oldLength; i++)
|
||||||
|
{
|
||||||
|
if (oldArray[i] != value)
|
||||||
|
newArray[j++] = oldArray[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_array = newArray;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(uint id)
|
return false;
|
||||||
{
|
|
||||||
lock (m_clients)
|
|
||||||
{
|
|
||||||
m_clients.Remove(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(uint id, IClientAPI client)
|
/// <summary>
|
||||||
|
/// Resets the client collection
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
{
|
{
|
||||||
lock (m_clients)
|
lock (m_syncRoot)
|
||||||
{
|
{
|
||||||
m_clients.Add(id, client);
|
m_dict1.Clear();
|
||||||
|
m_dict2.Clear();
|
||||||
|
m_array = new IClientAPI[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pass incoming packet to client.
|
/// Checks if a UUID is in the collection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="circuitCode">uint identifying the connection/client.</param>
|
/// <param name="key">UUID to check for</param>
|
||||||
/// <param name="packet">object containing the packet.</param>
|
/// <returns>True if the UUID was found in the collection, otherwise false</returns>
|
||||||
public void InPacket(uint circuitCode, object packet)
|
public bool ContainsKey(UUID key)
|
||||||
{
|
{
|
||||||
IClientAPI client;
|
return m_dict1.ContainsKey(key);
|
||||||
bool tryGetRet = false;
|
}
|
||||||
|
|
||||||
lock (m_clients)
|
/// <summary>
|
||||||
tryGetRet = m_clients.TryGetValue(circuitCode, out client);
|
/// Checks if an endpoint is in the collection
|
||||||
|
/// </summary>
|
||||||
if (tryGetRet)
|
/// <param name="key">Endpoint to check for</param>
|
||||||
|
/// <returns>True if the endpoint was found in the collection, otherwise false</returns>
|
||||||
|
public bool ContainsKey(IPEndPoint key)
|
||||||
{
|
{
|
||||||
client.InPacket(packet);
|
return m_dict2.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to fetch a value out of the collection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">UUID of the client to retrieve</param>
|
||||||
|
/// <param name="value">Retrieved client, or null on lookup failure</param>
|
||||||
|
/// <returns>True if the lookup succeeded, otherwise false</returns>
|
||||||
|
public bool TryGetValue(UUID key, out IClientAPI value)
|
||||||
|
{
|
||||||
|
try { return m_dict1.TryGetValue(key, out value); }
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CloseAllAgents(uint circuitCode)
|
/// <summary>
|
||||||
|
/// Attempts to fetch a value out of the collection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">Endpoint of the client to retrieve</param>
|
||||||
|
/// <param name="value">Retrieved client, or null on lookup failure</param>
|
||||||
|
/// <returns>True if the lookup succeeded, otherwise false</returns>
|
||||||
|
public bool TryGetValue(IPEndPoint key, out IClientAPI value)
|
||||||
{
|
{
|
||||||
IClientAPI client;
|
try { return m_dict2.TryGetValue(key, out value); }
|
||||||
bool tryGetRet = false;
|
catch (Exception)
|
||||||
lock (m_clients)
|
|
||||||
tryGetRet = m_clients.TryGetValue(circuitCode, out client);
|
|
||||||
if (tryGetRet)
|
|
||||||
{
|
{
|
||||||
CloseAllCircuits(client.AgentId);
|
value = null;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CloseAllCircuits(UUID agentId)
|
/// <summary>
|
||||||
|
/// Performs a given task in parallel for each of the elements in the
|
||||||
|
/// collection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="action">Action to perform on each element</param>
|
||||||
|
public void ForEach(Action<IClientAPI> action)
|
||||||
{
|
{
|
||||||
uint[] circuits = GetAllCircuits(agentId);
|
IClientAPI[] localArray = m_array;
|
||||||
// We're using a for loop here so changes to the circuits don't cause it to completely fail.
|
Parallel.ForEach<IClientAPI>(localArray, action);
|
||||||
|
|
||||||
for (int i = 0; i < circuits.Length; i++)
|
|
||||||
{
|
|
||||||
IClientAPI client;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bool tryGetRet = false;
|
|
||||||
lock (m_clients)
|
|
||||||
tryGetRet = m_clients.TryGetValue(circuits[i], out client);
|
|
||||||
if (tryGetRet)
|
|
||||||
{
|
|
||||||
Remove(client.CircuitCode);
|
|
||||||
client.Close(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
m_log.Error(string.Format("[CLIENT]: Unable to shutdown circuit for: {0}\n Reason: {1}", agentId, e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// [Obsolete("Using Obsolete to drive development is invalid. Obsolete presumes that something new has already been created to replace this.")]
|
/// <summary>
|
||||||
public uint[] GetAllCircuits(UUID agentId)
|
/// Performs a given task synchronously for each of the elements in
|
||||||
|
/// the collection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="action">Action to perform on each element</param>
|
||||||
|
public void ForEachSync(Action<IClientAPI> action)
|
||||||
{
|
{
|
||||||
List<uint> circuits = new List<uint>();
|
IClientAPI[] localArray = m_array;
|
||||||
// Wasteful, I know
|
for (int i = 0; i < localArray.Length; i++)
|
||||||
IClientAPI[] LocalClients = new IClientAPI[0];
|
action(localArray[i]);
|
||||||
lock (m_clients)
|
|
||||||
{
|
|
||||||
LocalClients = new IClientAPI[m_clients.Count];
|
|
||||||
m_clients.Values.CopyTo(LocalClients, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < LocalClients.Length; i++)
|
|
||||||
{
|
|
||||||
if (LocalClients[i].AgentId == agentId)
|
|
||||||
{
|
|
||||||
circuits.Add(LocalClients[i].CircuitCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return circuits.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<uint> GetAllCircuitCodes()
|
|
||||||
{
|
|
||||||
List<uint> circuits;
|
|
||||||
|
|
||||||
lock (m_clients)
|
|
||||||
{
|
|
||||||
circuits = new List<uint>(m_clients.Keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
return circuits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ViewerEffectHandler(IClientAPI sender, List<ViewerEffectEventHandlerArg> args)
|
|
||||||
{
|
|
||||||
// TODO: don't create new blocks if recycling an old packet
|
|
||||||
List<ViewerEffectPacket.EffectBlock> effectBlock = new List<ViewerEffectPacket.EffectBlock>();
|
|
||||||
for (int i = 0; i < args.Count; i++)
|
|
||||||
{
|
|
||||||
ViewerEffectPacket.EffectBlock effect = new ViewerEffectPacket.EffectBlock();
|
|
||||||
effect.AgentID = args[i].AgentID;
|
|
||||||
effect.Color = args[i].Color;
|
|
||||||
effect.Duration = args[i].Duration;
|
|
||||||
effect.ID = args[i].ID;
|
|
||||||
effect.Type = args[i].Type;
|
|
||||||
effect.TypeData = args[i].TypeData;
|
|
||||||
effectBlock.Add(effect);
|
|
||||||
}
|
|
||||||
ViewerEffectPacket.EffectBlock[] effectBlockArray = effectBlock.ToArray();
|
|
||||||
|
|
||||||
IClientAPI[] LocalClients;
|
|
||||||
lock (m_clients)
|
|
||||||
{
|
|
||||||
LocalClients = new IClientAPI[m_clients.Count];
|
|
||||||
m_clients.Values.CopyTo(LocalClients, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < LocalClients.Length; i++)
|
|
||||||
{
|
|
||||||
if (LocalClients[i].AgentId != sender.AgentId)
|
|
||||||
{
|
|
||||||
LocalClients[i].SendViewerEffect(effectBlockArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetClient(uint circuitId, out IClientAPI user)
|
|
||||||
{
|
|
||||||
lock (m_clients)
|
|
||||||
{
|
|
||||||
return m_clients.TryGetValue(circuitId, out user);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,6 +146,7 @@ namespace OpenSim.Framework.Communications
|
||||||
// If the operation isn't done, wait for it
|
// If the operation isn't done, wait for it
|
||||||
AsyncWaitHandle.WaitOne();
|
AsyncWaitHandle.WaitOne();
|
||||||
AsyncWaitHandle.Close();
|
AsyncWaitHandle.Close();
|
||||||
|
m_waitHandle.Close();
|
||||||
m_waitHandle = null; // Allow early GC
|
m_waitHandle = null; // Allow early GC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ namespace OpenSim.Framework.Communications
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This flag will help block the main synchroneous method, in case we run in synchroneous mode
|
/// This flag will help block the main synchroneous method, in case we run in synchroneous mode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static ManualResetEvent _allDone = new ManualResetEvent(false);
|
//public static ManualResetEvent _allDone = new ManualResetEvent(false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default time out period
|
/// Default time out period
|
||||||
|
@ -282,12 +282,12 @@ namespace OpenSim.Framework.Communications
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
s.Close();
|
s.Close();
|
||||||
_allDone.Set();
|
//_allDone.Set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_allDone.Set();
|
//_allDone.Set();
|
||||||
_asyncException = e;
|
_asyncException = e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -561,6 +561,8 @@ namespace OpenSim.Framework
|
||||||
// [Obsolete("LLClientView Specific - Circuits are unique to LLClientView")]
|
// [Obsolete("LLClientView Specific - Circuits are unique to LLClientView")]
|
||||||
uint CircuitCode { get; }
|
uint CircuitCode { get; }
|
||||||
|
|
||||||
|
IPEndPoint RemoteEndPoint { get; }
|
||||||
|
|
||||||
event GenericMessage OnGenericMessage;
|
event GenericMessage OnGenericMessage;
|
||||||
|
|
||||||
// [Obsolete("LLClientView Specific - Replace with more bare-bones arguments.")]
|
// [Obsolete("LLClientView Specific - Replace with more bare-bones arguments.")]
|
||||||
|
@ -802,7 +804,7 @@ namespace OpenSim.Framework
|
||||||
|
|
||||||
void InPacket(object NewPack);
|
void InPacket(object NewPack);
|
||||||
void ProcessInPacket(Packet NewPack);
|
void ProcessInPacket(Packet NewPack);
|
||||||
void Close(bool ShutdownCircuit);
|
void Close();
|
||||||
void Kick(string message);
|
void Kick(string message);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -71,7 +71,6 @@ namespace OpenSim.Framework
|
||||||
|
|
||||||
void AddNewClient(IClientAPI client);
|
void AddNewClient(IClientAPI client);
|
||||||
void RemoveClient(UUID agentID);
|
void RemoveClient(UUID agentID);
|
||||||
void CloseAllAgents(uint circuitcode);
|
|
||||||
|
|
||||||
void Restart(int seconds);
|
void Restart(int seconds);
|
||||||
//RegionInfo OtherRegionUp(RegionInfo thisRegion);
|
//RegionInfo OtherRegionUp(RegionInfo thisRegion);
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, openmetaverse.org
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* - 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.
|
||||||
|
* - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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.Threading;
|
||||||
|
|
||||||
|
namespace OpenSim.Framework
|
||||||
|
{
|
||||||
|
public sealed class LocklessQueue<T>
|
||||||
|
{
|
||||||
|
private sealed class SingleLinkNode
|
||||||
|
{
|
||||||
|
public SingleLinkNode Next;
|
||||||
|
public T Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
SingleLinkNode head;
|
||||||
|
SingleLinkNode tail;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
public int Count { get { return count; } }
|
||||||
|
|
||||||
|
public LocklessQueue()
|
||||||
|
{
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Enqueue(T item)
|
||||||
|
{
|
||||||
|
SingleLinkNode oldTail = null;
|
||||||
|
SingleLinkNode oldTailNext;
|
||||||
|
|
||||||
|
SingleLinkNode newNode = new SingleLinkNode();
|
||||||
|
newNode.Item = item;
|
||||||
|
|
||||||
|
bool newNodeWasAdded = false;
|
||||||
|
|
||||||
|
while (!newNodeWasAdded)
|
||||||
|
{
|
||||||
|
oldTail = tail;
|
||||||
|
oldTailNext = oldTail.Next;
|
||||||
|
|
||||||
|
if (tail == oldTail)
|
||||||
|
{
|
||||||
|
if (oldTailNext == null)
|
||||||
|
newNodeWasAdded = CAS(ref tail.Next, null, newNode);
|
||||||
|
else
|
||||||
|
CAS(ref tail, oldTail, oldTailNext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CAS(ref tail, oldTail, newNode);
|
||||||
|
Interlocked.Increment(ref count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Dequeue(out T item)
|
||||||
|
{
|
||||||
|
item = default(T);
|
||||||
|
SingleLinkNode oldHead = null;
|
||||||
|
bool haveAdvancedHead = false;
|
||||||
|
|
||||||
|
while (!haveAdvancedHead)
|
||||||
|
{
|
||||||
|
oldHead = head;
|
||||||
|
SingleLinkNode oldTail = tail;
|
||||||
|
SingleLinkNode oldHeadNext = oldHead.Next;
|
||||||
|
|
||||||
|
if (oldHead == head)
|
||||||
|
{
|
||||||
|
if (oldHead == oldTail)
|
||||||
|
{
|
||||||
|
if (oldHeadNext == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CAS(ref tail, oldTail, oldHeadNext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item = oldHeadNext.Item;
|
||||||
|
haveAdvancedHead = CAS(ref head, oldHead, oldHeadNext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Interlocked.Decrement(ref count);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Init()
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
head = tail = new SingleLinkNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool CAS(ref SingleLinkNode location, SingleLinkNode comparand, SingleLinkNode newValue)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(object)comparand ==
|
||||||
|
(object)Interlocked.CompareExchange<SingleLinkNode>(ref location, newValue, comparand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -89,6 +89,7 @@ namespace OpenSim.Framework
|
||||||
}
|
}
|
||||||
|
|
||||||
threadFinishEvent.WaitOne();
|
threadFinishEvent.WaitOne();
|
||||||
|
threadFinishEvent.Close();
|
||||||
|
|
||||||
if (exception != null)
|
if (exception != null)
|
||||||
throw new Exception(exception.Message, exception);
|
throw new Exception(exception.Message, exception);
|
||||||
|
@ -148,6 +149,7 @@ namespace OpenSim.Framework
|
||||||
}
|
}
|
||||||
|
|
||||||
threadFinishEvent.WaitOne();
|
threadFinishEvent.WaitOne();
|
||||||
|
threadFinishEvent.Close();
|
||||||
|
|
||||||
if (exception != null)
|
if (exception != null)
|
||||||
throw new Exception(exception.Message, exception);
|
throw new Exception(exception.Message, exception);
|
||||||
|
@ -199,6 +201,7 @@ namespace OpenSim.Framework
|
||||||
}
|
}
|
||||||
|
|
||||||
threadFinishEvent.WaitOne();
|
threadFinishEvent.WaitOne();
|
||||||
|
threadFinishEvent.Close();
|
||||||
|
|
||||||
if (exception != null)
|
if (exception != null)
|
||||||
throw new Exception(exception.Message, exception);
|
throw new Exception(exception.Message, exception);
|
||||||
|
|
|
@ -31,13 +31,24 @@ namespace OpenSim.Framework
|
||||||
{
|
{
|
||||||
public enum ThrottleOutPacketType : int
|
public enum ThrottleOutPacketType : int
|
||||||
{
|
{
|
||||||
Unknown = -1, // Also doubles as 'do not throttle'
|
/// <summary>Unthrottled packets</summary>
|
||||||
|
Unknown = -1,
|
||||||
|
/// <summary>Packets that are being resent</summary>
|
||||||
Resend = 0,
|
Resend = 0,
|
||||||
|
/// <summary>Terrain data</summary>
|
||||||
Land = 1,
|
Land = 1,
|
||||||
|
/// <summary>Wind data</summary>
|
||||||
Wind = 2,
|
Wind = 2,
|
||||||
|
/// <summary>Cloud data</summary>
|
||||||
Cloud = 3,
|
Cloud = 3,
|
||||||
|
/// <summary>Any packets that do not fit into the other throttles</summary>
|
||||||
Task = 4,
|
Task = 4,
|
||||||
|
/// <summary>Texture assets</summary>
|
||||||
Texture = 5,
|
Texture = 5,
|
||||||
|
/// <summary>Non-texture assets</summary>
|
||||||
Asset = 6,
|
Asset = 6,
|
||||||
|
/// <summary>Avatar and primitive data</summary>
|
||||||
|
/// <remarks>This is a sub-category of Task</remarks>
|
||||||
|
State = 7,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,6 +239,10 @@ namespace OpenSim
|
||||||
"show users [full]",
|
"show users [full]",
|
||||||
"Show user data", HandleShow);
|
"Show user data", HandleShow);
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand("region", false, "show connections",
|
||||||
|
"show connections",
|
||||||
|
"Show connection data", HandleShow);
|
||||||
|
|
||||||
m_console.Commands.AddCommand("region", false, "show users full",
|
m_console.Commands.AddCommand("region", false, "show users full",
|
||||||
"show users full",
|
"show users full",
|
||||||
String.Empty, HandleShow);
|
String.Empty, HandleShow);
|
||||||
|
@ -921,7 +925,25 @@ namespace OpenSim
|
||||||
regionName));
|
regionName));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.Info("");
|
m_log.Info(String.Empty);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "connections":
|
||||||
|
System.Text.StringBuilder connections = new System.Text.StringBuilder("Connections:\n");
|
||||||
|
m_sceneManager.ForEachScene(
|
||||||
|
delegate(Scene scene)
|
||||||
|
{
|
||||||
|
scene.ClientManager.ForEachSync(
|
||||||
|
delegate(IClientAPI client)
|
||||||
|
{
|
||||||
|
connections.AppendFormat("{0}: {1} ({2}) from {3} on circuit {4}\n",
|
||||||
|
scene.RegionInfo.RegionName, client.Name, client.AgentId, client.RemoteEndPoint, client.CircuitCode);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
m_log.Info(connections.ToString());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "modules":
|
case "modules":
|
||||||
|
|
|
@ -58,6 +58,7 @@ namespace OpenSim
|
||||||
m_clientServers.Count.ToString(), m_clientServers.Count > 1 ? "s" : "");
|
m_clientServers.Count.ToString(), m_clientServers.Count > 1 ? "s" : "");
|
||||||
|
|
||||||
WorldHasComeToAnEnd.WaitOne();
|
WorldHasComeToAnEnd.WaitOne();
|
||||||
|
WorldHasComeToAnEnd.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -31,6 +31,7 @@ using OpenMetaverse;
|
||||||
using OpenMetaverse.Imaging;
|
using OpenMetaverse.Imaging;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Region.Framework.Interfaces;
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
using OpenSim.Region.Framework.Scenes.Hypergrid;
|
||||||
using OpenSim.Services.Interfaces;
|
using OpenSim.Services.Interfaces;
|
||||||
using log4net;
|
using log4net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
@ -54,6 +55,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
public UUID TextureID;
|
public UUID TextureID;
|
||||||
public IJ2KDecoder J2KDecoder;
|
public IJ2KDecoder J2KDecoder;
|
||||||
public IAssetService AssetService;
|
public IAssetService AssetService;
|
||||||
|
public UUID AgentID;
|
||||||
|
public IHyperAssetService HyperAssets;
|
||||||
public OpenJPEG.J2KLayerInfo[] Layers;
|
public OpenJPEG.J2KLayerInfo[] Layers;
|
||||||
public bool IsDecoded;
|
public bool IsDecoded;
|
||||||
public bool HasAsset;
|
public bool HasAsset;
|
||||||
|
@ -72,14 +75,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
m_imageManager = imageManager;
|
m_imageManager = imageManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SendPackets(LLClientView client, int maxpack)
|
/// <summary>
|
||||||
|
/// Sends packets for this texture to a client until packetsToSend is
|
||||||
|
/// hit or the transfer completes
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">Reference to the client that the packets are destined for</param>
|
||||||
|
/// <param name="packetsToSend">Maximum number of packets to send during this call</param>
|
||||||
|
/// <param name="packetsSent">Number of packets sent during this call</param>
|
||||||
|
/// <returns>True if the transfer completes at the current discard level, otherwise false</returns>
|
||||||
|
public bool SendPackets(LLClientView client, int packetsToSend, out int packetsSent)
|
||||||
{
|
{
|
||||||
if (client == null)
|
packetsSent = 0;
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_currentPacket <= m_stopPacket)
|
if (m_currentPacket <= m_stopPacket)
|
||||||
{
|
{
|
||||||
int count = 0;
|
|
||||||
bool sendMore = true;
|
bool sendMore = true;
|
||||||
|
|
||||||
if (!m_sentInfo || (m_currentPacket == 0))
|
if (!m_sentInfo || (m_currentPacket == 0))
|
||||||
|
@ -88,25 +97,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
m_sentInfo = true;
|
m_sentInfo = true;
|
||||||
++m_currentPacket;
|
++m_currentPacket;
|
||||||
++count;
|
++packetsSent;
|
||||||
}
|
}
|
||||||
if (m_currentPacket < 2)
|
if (m_currentPacket < 2)
|
||||||
{
|
{
|
||||||
m_currentPacket = 2;
|
m_currentPacket = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (sendMore && count < maxpack && m_currentPacket <= m_stopPacket)
|
while (sendMore && packetsSent < packetsToSend && m_currentPacket <= m_stopPacket)
|
||||||
{
|
{
|
||||||
sendMore = SendPacket(client);
|
sendMore = SendPacket(client);
|
||||||
++m_currentPacket;
|
++m_currentPacket;
|
||||||
++count;
|
++packetsSent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_currentPacket > m_stopPacket)
|
return (m_currentPacket > m_stopPacket);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RunUpdate()
|
public void RunUpdate()
|
||||||
|
@ -370,6 +376,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
UUID assetID = UUID.Zero;
|
UUID assetID = UUID.Zero;
|
||||||
if (asset != null)
|
if (asset != null)
|
||||||
assetID = asset.FullID;
|
assetID = asset.FullID;
|
||||||
|
else if ((HyperAssets != null) && (sender != HyperAssets))
|
||||||
|
{
|
||||||
|
// Try the user's inventory, but only if it's different from the regions'
|
||||||
|
string userAssets = HyperAssets.GetUserAssetServer(AgentID);
|
||||||
|
if ((userAssets != string.Empty) && (userAssets != HyperAssets.GetSimAssetServer()))
|
||||||
|
{
|
||||||
|
m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", id);
|
||||||
|
AssetService.Get(userAssets + "/" + id, HyperAssets, AssetReceived);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AssetDataCallback(assetID, asset);
|
AssetDataCallback(assetID, asset);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -59,6 +59,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer());
|
private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer());
|
||||||
private object m_syncRoot = new object();
|
private object m_syncRoot = new object();
|
||||||
|
|
||||||
|
private IHyperAssetService m_hyperAssets;
|
||||||
|
|
||||||
public LLClientView Client { get { return m_client; } }
|
public LLClientView Client { get { return m_client; } }
|
||||||
public AssetBase MissingImage { get { return m_missingImage; } }
|
public AssetBase MissingImage { get { return m_missingImage; } }
|
||||||
|
|
||||||
|
@ -74,6 +76,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client");
|
m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client");
|
||||||
|
|
||||||
m_j2kDecodeModule = pJ2kDecodeModule;
|
m_j2kDecodeModule = pJ2kDecodeModule;
|
||||||
|
m_hyperAssets = client.Scene.RequestModuleInterface<IHyperAssetService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -146,6 +149,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
imgrequest = new J2KImage(this);
|
imgrequest = new J2KImage(this);
|
||||||
imgrequest.J2KDecoder = m_j2kDecodeModule;
|
imgrequest.J2KDecoder = m_j2kDecodeModule;
|
||||||
imgrequest.AssetService = m_assetCache;
|
imgrequest.AssetService = m_assetCache;
|
||||||
|
imgrequest.AgentID = m_client.AgentId;
|
||||||
|
imgrequest.HyperAssets = m_hyperAssets;
|
||||||
imgrequest.DiscardLevel = newRequest.DiscardLevel;
|
imgrequest.DiscardLevel = newRequest.DiscardLevel;
|
||||||
imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber);
|
imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber);
|
||||||
imgrequest.Priority = newRequest.Priority;
|
imgrequest.Priority = newRequest.Priority;
|
||||||
|
@ -162,47 +167,48 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ProcessImageQueue(int count, int maxpack)
|
public bool ProcessImageQueue(int packetsToSend)
|
||||||
{
|
{
|
||||||
J2KImage imagereq;
|
|
||||||
int numCollected = 0;
|
|
||||||
|
|
||||||
//lock (m_syncRoot)
|
|
||||||
//{
|
|
||||||
m_lastloopprocessed = DateTime.Now.Ticks;
|
m_lastloopprocessed = DateTime.Now.Ticks;
|
||||||
|
int packetsSent = 0;
|
||||||
|
|
||||||
// This can happen during Close()
|
while (packetsSent < packetsToSend)
|
||||||
if (m_client == null)
|
{
|
||||||
|
J2KImage image = GetHighestPriorityImage();
|
||||||
|
|
||||||
|
// If null was returned, the texture priority queue is currently empty
|
||||||
|
if (image == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
while ((imagereq = GetHighestPriorityImage()) != null)
|
if (image.IsDecoded)
|
||||||
{
|
{
|
||||||
if (imagereq.IsDecoded == true)
|
int sent;
|
||||||
{
|
bool imageDone = image.SendPackets(m_client, packetsToSend - packetsSent, out sent);
|
||||||
++numCollected;
|
packetsSent += sent;
|
||||||
|
|
||||||
if (imagereq.SendPackets(m_client, maxpack))
|
// If the send is complete, destroy any knowledge of this transfer
|
||||||
|
if (imageDone)
|
||||||
|
RemoveImageFromQueue(image);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// Send complete. Destroy any knowledge of this transfer
|
// TODO: This is a limitation of how LLImageManager is currently
|
||||||
RemoveImageFromQueue(imagereq);
|
// written. Undecoded textures should not be going into the priority
|
||||||
|
// queue, because a high priority undecoded texture will clog up the
|
||||||
|
// pipeline for a client
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numCollected == count)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//}
|
|
||||||
|
|
||||||
return m_priorityQueue.Count > 0;
|
return m_priorityQueue.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Faux destructor
|
/// <summary>
|
||||||
|
/// Faux destructor
|
||||||
|
/// </summary>
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
m_shuttingdown = true;
|
m_shuttingdown = true;
|
||||||
m_j2kDecodeModule = null;
|
|
||||||
m_assetCache = null;
|
|
||||||
m_client = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Priority Queue Helpers
|
#region Priority Queue Helpers
|
||||||
|
@ -213,13 +219,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
lock (m_syncRoot)
|
lock (m_syncRoot)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (m_priorityQueue.Count > 0)
|
if (m_priorityQueue.Count > 0)
|
||||||
{
|
{
|
||||||
try
|
try { image = m_priorityQueue.FindMax(); }
|
||||||
{
|
|
||||||
image = m_priorityQueue.FindMax();
|
|
||||||
}
|
|
||||||
catch (Exception) { }
|
catch (Exception) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,20 +233,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
image.PriorityQueueHandle = null;
|
image.PriorityQueueHandle = null;
|
||||||
|
|
||||||
lock (m_syncRoot)
|
lock (m_syncRoot)
|
||||||
try
|
try { m_priorityQueue.Add(ref image.PriorityQueueHandle, image); }
|
||||||
{
|
|
||||||
m_priorityQueue.Add(ref image.PriorityQueueHandle, image);
|
|
||||||
}
|
|
||||||
catch (Exception) { }
|
catch (Exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveImageFromQueue(J2KImage image)
|
void RemoveImageFromQueue(J2KImage image)
|
||||||
{
|
{
|
||||||
lock (m_syncRoot)
|
lock (m_syncRoot)
|
||||||
try
|
try { m_priorityQueue.Delete(image.PriorityQueueHandle); }
|
||||||
{
|
|
||||||
m_priorityQueue.Delete(image.PriorityQueueHandle);
|
|
||||||
}
|
|
||||||
catch (Exception) { }
|
catch (Exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using log4net;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
using OpenMetaverse.Packets;
|
||||||
|
|
||||||
namespace OpenSim.Region.ClientStack.LindenUDP
|
namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
|
@ -59,9 +61,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class LLUDPClient
|
public sealed class LLUDPClient
|
||||||
{
|
{
|
||||||
|
// TODO: Make this a config setting
|
||||||
|
/// <summary>Percentage of the task throttle category that is allocated to avatar and prim
|
||||||
|
/// state updates</summary>
|
||||||
|
const float STATE_TASK_PERCENTAGE = 0.8f;
|
||||||
|
|
||||||
|
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
/// <summary>The number of packet categories to throttle on. If a throttle category is added
|
/// <summary>The number of packet categories to throttle on. If a throttle category is added
|
||||||
/// or removed, this number must also change</summary>
|
/// or removed, this number must also change</summary>
|
||||||
const int THROTTLE_CATEGORY_COUNT = 7;
|
const int THROTTLE_CATEGORY_COUNT = 8;
|
||||||
|
|
||||||
/// <summary>Fired when updated networking stats are produced for this client</summary>
|
/// <summary>Fired when updated networking stats are produced for this client</summary>
|
||||||
public event PacketStats OnPacketStats;
|
public event PacketStats OnPacketStats;
|
||||||
|
@ -80,10 +89,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// <summary>Packets we have sent that need to be ACKed by the client</summary>
|
/// <summary>Packets we have sent that need to be ACKed by the client</summary>
|
||||||
public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
|
public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
|
||||||
/// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
|
/// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
|
||||||
public readonly LocklessQueue<uint> PendingAcks = new LocklessQueue<uint>();
|
public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>();
|
||||||
|
|
||||||
/// <summary>Reference to the IClientAPI for this client</summary>
|
|
||||||
public LLClientView ClientAPI;
|
|
||||||
/// <summary>Current packet sequence number</summary>
|
/// <summary>Current packet sequence number</summary>
|
||||||
public int CurrentSequence;
|
public int CurrentSequence;
|
||||||
/// <summary>Current ping sequence number</summary>
|
/// <summary>Current ping sequence number</summary>
|
||||||
|
@ -123,21 +130,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
private int m_packetsSentReported;
|
private int m_packetsSentReported;
|
||||||
|
|
||||||
/// <summary>Throttle bucket for this agent's connection</summary>
|
/// <summary>Throttle bucket for this agent's connection</summary>
|
||||||
private readonly TokenBucket throttle;
|
private readonly TokenBucket m_throttle;
|
||||||
/// <summary>Throttle buckets for each packet category</summary>
|
/// <summary>Throttle buckets for each packet category</summary>
|
||||||
private readonly TokenBucket[] throttleCategories;
|
private readonly TokenBucket[] m_throttleCategories;
|
||||||
/// <summary>Throttle rate defaults and limits</summary>
|
/// <summary>Throttle rate defaults and limits</summary>
|
||||||
private readonly ThrottleRates defaultThrottleRates;
|
private readonly ThrottleRates m_defaultThrottleRates;
|
||||||
/// <summary>Outgoing queues for throttled packets</summary>
|
/// <summary>Outgoing queues for throttled packets</summary>
|
||||||
private readonly LocklessQueue<OutgoingPacket>[] packetOutboxes = new LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT];
|
private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT];
|
||||||
/// <summary>A container that can hold one packet for each outbox, used to store
|
/// <summary>A container that can hold one packet for each outbox, used to store
|
||||||
/// dequeued packets that are being held for throttling</summary>
|
/// dequeued packets that are being held for throttling</summary>
|
||||||
private readonly OutgoingPacket[] nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
|
private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
|
||||||
/// <summary>An optimization to store the length of dequeued packets being held
|
/// <summary>Flags to prevent queue empty callbacks from stacking up on
|
||||||
/// for throttling. This avoids expensive calls to Packet.Length</summary>
|
/// top of each other</summary>
|
||||||
private readonly int[] nextPacketLengths = new int[THROTTLE_CATEGORY_COUNT];
|
private readonly bool[] m_onQueueEmptyRunning = new bool[THROTTLE_CATEGORY_COUNT];
|
||||||
/// <summary>A reference to the LLUDPServer that is managing this client</summary>
|
/// <summary>A reference to the LLUDPServer that is managing this client</summary>
|
||||||
private readonly LLUDPServer udpServer;
|
private readonly LLUDPServer m_udpServer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
|
@ -151,24 +158,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// <param name="remoteEndPoint">Remote endpoint for this connection</param>
|
/// <param name="remoteEndPoint">Remote endpoint for this connection</param>
|
||||||
public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint)
|
public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint)
|
||||||
{
|
{
|
||||||
udpServer = server;
|
|
||||||
AgentID = agentID;
|
AgentID = agentID;
|
||||||
RemoteEndPoint = remoteEndPoint;
|
RemoteEndPoint = remoteEndPoint;
|
||||||
CircuitCode = circuitCode;
|
CircuitCode = circuitCode;
|
||||||
defaultThrottleRates = rates;
|
m_udpServer = server;
|
||||||
|
m_defaultThrottleRates = rates;
|
||||||
|
m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total);
|
||||||
|
m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
|
||||||
|
|
||||||
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
|
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
|
||||||
packetOutboxes[i] = new LocklessQueue<OutgoingPacket>();
|
{
|
||||||
|
ThrottleOutPacketType type = (ThrottleOutPacketType)i;
|
||||||
|
|
||||||
throttle = new TokenBucket(parentThrottle, 0, 0);
|
m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
|
||||||
throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
|
m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type));
|
||||||
throttleCategories[(int)ThrottleOutPacketType.Resend] = new TokenBucket(throttle, rates.ResendLimit, rates.Resend);
|
}
|
||||||
throttleCategories[(int)ThrottleOutPacketType.Land] = new TokenBucket(throttle, rates.LandLimit, rates.Land);
|
|
||||||
throttleCategories[(int)ThrottleOutPacketType.Wind] = new TokenBucket(throttle, rates.WindLimit, rates.Wind);
|
|
||||||
throttleCategories[(int)ThrottleOutPacketType.Cloud] = new TokenBucket(throttle, rates.CloudLimit, rates.Cloud);
|
|
||||||
throttleCategories[(int)ThrottleOutPacketType.Task] = new TokenBucket(throttle, rates.TaskLimit, rates.Task);
|
|
||||||
throttleCategories[(int)ThrottleOutPacketType.Texture] = new TokenBucket(throttle, rates.TextureLimit, rates.Texture);
|
|
||||||
throttleCategories[(int)ThrottleOutPacketType.Asset] = new TokenBucket(throttle, rates.AssetLimit, rates.Asset);
|
|
||||||
|
|
||||||
// Set the granularity variable used for retransmission calculations to
|
// Set the granularity variable used for retransmission calculations to
|
||||||
// the measured resolution of Environment.TickCount
|
// the measured resolution of Environment.TickCount
|
||||||
|
@ -176,6 +180,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
// Default the retransmission timeout to three seconds
|
// Default the retransmission timeout to three seconds
|
||||||
RTO = 3000;
|
RTO = 3000;
|
||||||
|
|
||||||
|
// Initialize this to a sane value to prevent early disconnects
|
||||||
|
TickLastPacketReceived = Environment.TickCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -183,8 +190,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Shutdown()
|
public void Shutdown()
|
||||||
{
|
{
|
||||||
// TODO: Do we need to invalidate the circuit?
|
|
||||||
IsConnected = false;
|
IsConnected = false;
|
||||||
|
NeedAcks.Clear();
|
||||||
|
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
|
||||||
|
{
|
||||||
|
m_packetOutboxes[i].Clear();
|
||||||
|
m_nextPackets[i] = null;
|
||||||
|
}
|
||||||
|
OnPacketStats = null;
|
||||||
|
OnQueueEmpty = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -200,13 +214,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
info.pendingAcks = new Dictionary<uint, uint>();
|
info.pendingAcks = new Dictionary<uint, uint>();
|
||||||
info.needAck = new Dictionary<uint, byte[]>();
|
info.needAck = new Dictionary<uint, byte[]>();
|
||||||
|
|
||||||
info.resendThrottle = throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
|
info.resendThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
|
||||||
info.landThrottle = throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
|
info.landThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
|
||||||
info.windThrottle = throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
|
info.windThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
|
||||||
info.cloudThrottle = throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
|
info.cloudThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
|
||||||
info.taskThrottle = throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
|
info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
|
||||||
info.assetThrottle = throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
|
info.assetThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
|
||||||
info.textureThrottle = throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
|
info.textureThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
|
||||||
info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle +
|
info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle +
|
||||||
info.taskThrottle + info.assetThrottle + info.textureThrottle;
|
info.taskThrottle + info.assetThrottle + info.textureThrottle;
|
||||||
|
|
||||||
|
@ -267,6 +281,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
adjData = throttleData;
|
adjData = throttleData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 0.125f converts from bits to bytes
|
||||||
int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
||||||
int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
||||||
int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
||||||
|
@ -274,22 +289,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
||||||
int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
||||||
int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
|
int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
|
||||||
|
// State is a subcategory of task that we allocate a percentage to
|
||||||
|
int state = (int)((float)task * STATE_TASK_PERCENTAGE);
|
||||||
|
task -= state;
|
||||||
|
|
||||||
resend = (resend <= defaultThrottleRates.ResendLimit) ? resend : defaultThrottleRates.ResendLimit;
|
int ceiling = Int32.MaxValue;
|
||||||
land = (land <= defaultThrottleRates.LandLimit) ? land : defaultThrottleRates.LandLimit;
|
if (m_defaultThrottleRates.Total != 0)
|
||||||
wind = (wind <= defaultThrottleRates.WindLimit) ? wind : defaultThrottleRates.WindLimit;
|
{
|
||||||
cloud = (cloud <= defaultThrottleRates.CloudLimit) ? cloud : defaultThrottleRates.CloudLimit;
|
ceiling = m_defaultThrottleRates.Total;
|
||||||
task = (task <= defaultThrottleRates.TaskLimit) ? task : defaultThrottleRates.TaskLimit;
|
if (ceiling < Packet.MTU) ceiling = Packet.MTU;
|
||||||
texture = (texture <= defaultThrottleRates.TextureLimit) ? texture : defaultThrottleRates.TextureLimit;
|
}
|
||||||
asset = (asset <= defaultThrottleRates.AssetLimit) ? asset : defaultThrottleRates.AssetLimit;
|
|
||||||
|
|
||||||
SetThrottle(ThrottleOutPacketType.Resend, resend);
|
resend = Utils.Clamp(resend, Packet.MTU, ceiling);
|
||||||
SetThrottle(ThrottleOutPacketType.Land, land);
|
land = Utils.Clamp(land, Packet.MTU, ceiling);
|
||||||
SetThrottle(ThrottleOutPacketType.Wind, wind);
|
wind = Utils.Clamp(wind, Packet.MTU, ceiling);
|
||||||
SetThrottle(ThrottleOutPacketType.Cloud, cloud);
|
cloud = Utils.Clamp(cloud, Packet.MTU, ceiling);
|
||||||
SetThrottle(ThrottleOutPacketType.Task, task);
|
task = Utils.Clamp(task, Packet.MTU, ceiling);
|
||||||
SetThrottle(ThrottleOutPacketType.Texture, texture);
|
texture = Utils.Clamp(texture, Packet.MTU, ceiling);
|
||||||
SetThrottle(ThrottleOutPacketType.Asset, asset);
|
asset = Utils.Clamp(asset, Packet.MTU, ceiling);
|
||||||
|
state = Utils.Clamp(state, Packet.MTU, ceiling);
|
||||||
|
|
||||||
|
int total = resend + land + wind + cloud + task + texture + asset + state;
|
||||||
|
int taskTotal = task + state;
|
||||||
|
|
||||||
|
m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, State={8}, Total={9}",
|
||||||
|
AgentID, resend, land, wind, cloud, task, texture, asset, state, total);
|
||||||
|
|
||||||
|
SetThrottle(ThrottleOutPacketType.Resend, resend, resend);
|
||||||
|
SetThrottle(ThrottleOutPacketType.Land, land, land);
|
||||||
|
SetThrottle(ThrottleOutPacketType.Wind, wind, wind);
|
||||||
|
SetThrottle(ThrottleOutPacketType.Cloud, cloud, cloud);
|
||||||
|
SetThrottle(ThrottleOutPacketType.Task, task, taskTotal);
|
||||||
|
SetThrottle(ThrottleOutPacketType.Texture, texture, texture);
|
||||||
|
SetThrottle(ThrottleOutPacketType.Asset, asset, asset);
|
||||||
|
SetThrottle(ThrottleOutPacketType.State, state, taskTotal);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] GetThrottlesPacked()
|
public byte[] GetThrottlesPacked()
|
||||||
|
@ -297,25 +330,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
byte[] data = new byte[7 * 4];
|
byte[] data = new byte[7 * 4];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4;
|
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4;
|
||||||
Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4;
|
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4;
|
||||||
Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4;
|
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4;
|
||||||
Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4;
|
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4;
|
||||||
Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Task].DripRate), 0, data, i, 4); i += 4;
|
Buffer.BlockCopy(Utils.FloatToBytes((float)(m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) +
|
||||||
Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4;
|
m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4;
|
||||||
Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4;
|
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4;
|
||||||
|
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetThrottle(ThrottleOutPacketType category, int rate)
|
public void SetThrottle(ThrottleOutPacketType category, int rate, int maxBurst)
|
||||||
{
|
{
|
||||||
int i = (int)category;
|
int i = (int)category;
|
||||||
if (i >= 0 && i < throttleCategories.Length)
|
if (i >= 0 && i < m_throttleCategories.Length)
|
||||||
{
|
{
|
||||||
TokenBucket bucket = throttleCategories[(int)category];
|
TokenBucket bucket = m_throttleCategories[(int)category];
|
||||||
bucket.MaxBurst = rate;
|
|
||||||
bucket.DripRate = rate;
|
bucket.DripRate = rate;
|
||||||
|
bucket.MaxBurst = maxBurst;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,12 +357,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
int category = (int)packet.Category;
|
int category = (int)packet.Category;
|
||||||
|
|
||||||
if (category >= 0 && category < packetOutboxes.Length)
|
if (category >= 0 && category < m_packetOutboxes.Length)
|
||||||
{
|
{
|
||||||
LocklessQueue<OutgoingPacket> queue = packetOutboxes[category];
|
OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
|
||||||
TokenBucket bucket = throttleCategories[category];
|
TokenBucket bucket = m_throttleCategories[category];
|
||||||
|
|
||||||
if (throttleCategories[category].RemoveTokens(packet.Buffer.DataLength))
|
if (m_throttleCategories[category].RemoveTokens(packet.Buffer.DataLength))
|
||||||
{
|
{
|
||||||
// Enough tokens were removed from the bucket, the packet will not be queued
|
// Enough tokens were removed from the bucket, the packet will not be queued
|
||||||
return false;
|
return false;
|
||||||
|
@ -357,24 +391,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
public bool DequeueOutgoing()
|
public bool DequeueOutgoing()
|
||||||
{
|
{
|
||||||
OutgoingPacket packet;
|
OutgoingPacket packet;
|
||||||
LocklessQueue<OutgoingPacket> queue;
|
OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
|
||||||
TokenBucket bucket;
|
TokenBucket bucket;
|
||||||
bool packetSent = false;
|
bool packetSent = false;
|
||||||
|
|
||||||
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
|
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
|
||||||
{
|
{
|
||||||
bucket = throttleCategories[i];
|
bucket = m_throttleCategories[i];
|
||||||
|
|
||||||
if (nextPackets[i] != null)
|
if (m_nextPackets[i] != null)
|
||||||
{
|
{
|
||||||
// This bucket was empty the last time we tried to send a packet,
|
// This bucket was empty the last time we tried to send a packet,
|
||||||
// leaving a dequeued packet still waiting to be sent out. Try to
|
// leaving a dequeued packet still waiting to be sent out. Try to
|
||||||
// send it again
|
// send it again
|
||||||
if (bucket.RemoveTokens(nextPacketLengths[i]))
|
OutgoingPacket nextPacket = m_nextPackets[i];
|
||||||
|
if (bucket.RemoveTokens(nextPacket.Buffer.DataLength))
|
||||||
{
|
{
|
||||||
// Send the packet
|
// Send the packet
|
||||||
udpServer.SendPacketFinal(nextPackets[i]);
|
m_udpServer.SendPacketFinal(nextPacket);
|
||||||
nextPackets[i] = null;
|
m_nextPackets[i] = null;
|
||||||
packetSent = true;
|
packetSent = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -382,7 +417,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
// No dequeued packet waiting to be sent, try to pull one off
|
// No dequeued packet waiting to be sent, try to pull one off
|
||||||
// this queue
|
// this queue
|
||||||
queue = packetOutboxes[i];
|
queue = m_packetOutboxes[i];
|
||||||
if (queue.Dequeue(out packet))
|
if (queue.Dequeue(out packet))
|
||||||
{
|
{
|
||||||
// A packet was pulled off the queue. See if we have
|
// A packet was pulled off the queue. See if we have
|
||||||
|
@ -390,23 +425,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
if (bucket.RemoveTokens(packet.Buffer.DataLength))
|
if (bucket.RemoveTokens(packet.Buffer.DataLength))
|
||||||
{
|
{
|
||||||
// Send the packet
|
// Send the packet
|
||||||
udpServer.SendPacketFinal(packet);
|
m_udpServer.SendPacketFinal(packet);
|
||||||
packetSent = true;
|
packetSent = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Save the dequeued packet and the length calculation for
|
// Save the dequeued packet for the next iteration
|
||||||
// the next iteration
|
m_nextPackets[i] = packet;
|
||||||
nextPackets[i] = packet;
|
|
||||||
nextPacketLengths[i] = packet.Buffer.DataLength;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the queue is empty after this dequeue, fire the queue
|
||||||
|
// empty callback now so it has a chance to fill before we
|
||||||
|
// get back here
|
||||||
|
if (queue.Count == 0)
|
||||||
|
BeginFireQueueEmpty(i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// No packets in this queue. Fire the queue empty callback
|
// No packets in this queue. Fire the queue empty callback
|
||||||
QueueEmpty callback = OnQueueEmpty;
|
// if it has not been called recently
|
||||||
if (callback != null)
|
BeginFireQueueEmpty(i);
|
||||||
callback((ThrottleOutPacketType)i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -414,6 +452,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
return packetSent;
|
return packetSent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when an ACK packet is received and a round-trip time for a
|
||||||
|
/// packet is calculated. This is used to calculate the smoothed
|
||||||
|
/// round-trip time, round trip time variance, and finally the
|
||||||
|
/// retransmission timeout
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">Round-trip time of a single packet and its
|
||||||
|
/// acknowledgement</param>
|
||||||
public void UpdateRoundTrip(float r)
|
public void UpdateRoundTrip(float r)
|
||||||
{
|
{
|
||||||
const float ALPHA = 0.125f;
|
const float ALPHA = 0.125f;
|
||||||
|
@ -435,8 +481,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
// Always round retransmission timeout up to two seconds
|
// Always round retransmission timeout up to two seconds
|
||||||
RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR)));
|
RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR)));
|
||||||
//Logger.Debug("Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " +
|
//m_log.Debug("[LLUDPCLIENT]: Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " +
|
||||||
// RTTVAR + " based on new RTT of " + r + "ms");
|
// RTTVAR + " based on new RTT of " + r + "ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Does an early check to see if this queue empty callback is already
|
||||||
|
/// running, then asynchronously firing the event
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="throttleIndex">Throttle category to fire the callback
|
||||||
|
/// for</param>
|
||||||
|
private void BeginFireQueueEmpty(int throttleIndex)
|
||||||
|
{
|
||||||
|
if (!m_onQueueEmptyRunning[throttleIndex])
|
||||||
|
Util.FireAndForget(FireQueueEmpty, throttleIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks to see if this queue empty callback is already running,
|
||||||
|
/// then firing the event
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="o">Throttle category to fire the callback for, stored
|
||||||
|
/// as an object to match the WaitCallback delegate signature</param>
|
||||||
|
private void FireQueueEmpty(object o)
|
||||||
|
{
|
||||||
|
int i = (int)o;
|
||||||
|
ThrottleOutPacketType type = (ThrottleOutPacketType)i;
|
||||||
|
QueueEmpty callback = OnQueueEmpty;
|
||||||
|
|
||||||
|
if (callback != null)
|
||||||
|
{
|
||||||
|
if (!m_onQueueEmptyRunning[i])
|
||||||
|
{
|
||||||
|
m_onQueueEmptyRunning[i] = true;
|
||||||
|
try { callback(type); }
|
||||||
|
catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); }
|
||||||
|
m_onQueueEmptyRunning[i] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,282 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, http://opensimulator.org/
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSimulator Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net;
|
|
||||||
using OpenSim.Framework;
|
|
||||||
using OpenMetaverse;
|
|
||||||
|
|
||||||
using ReaderWriterLockImpl = OpenMetaverse.ReaderWriterLockSlim;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ClientStack.LindenUDP
|
|
||||||
{
|
|
||||||
public sealed class UDPClientCollection
|
|
||||||
{
|
|
||||||
Dictionary<UUID, LLUDPClient> Dictionary1;
|
|
||||||
Dictionary<IPEndPoint, LLUDPClient> Dictionary2;
|
|
||||||
LLUDPClient[] Array;
|
|
||||||
ReaderWriterLockImpl rwLock = new ReaderWriterLockImpl();
|
|
||||||
object m_sync = new object();
|
|
||||||
|
|
||||||
public UDPClientCollection()
|
|
||||||
{
|
|
||||||
Dictionary1 = new Dictionary<UUID, LLUDPClient>();
|
|
||||||
Dictionary2 = new Dictionary<IPEndPoint, LLUDPClient>();
|
|
||||||
Array = new LLUDPClient[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public UDPClientCollection(int capacity)
|
|
||||||
{
|
|
||||||
Dictionary1 = new Dictionary<UUID, LLUDPClient>(capacity);
|
|
||||||
Dictionary2 = new Dictionary<IPEndPoint, LLUDPClient>(capacity);
|
|
||||||
Array = new LLUDPClient[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(UUID key1, IPEndPoint key2, LLUDPClient value)
|
|
||||||
{
|
|
||||||
//rwLock.EnterWriteLock();
|
|
||||||
|
|
||||||
//try
|
|
||||||
//{
|
|
||||||
// if (Dictionary1.ContainsKey(key1))
|
|
||||||
// {
|
|
||||||
// if (!Dictionary2.ContainsKey(key2))
|
|
||||||
// throw new ArgumentException("key1 exists in the dictionary but not key2");
|
|
||||||
// }
|
|
||||||
// else if (Dictionary2.ContainsKey(key2))
|
|
||||||
// {
|
|
||||||
// if (!Dictionary1.ContainsKey(key1))
|
|
||||||
// throw new ArgumentException("key2 exists in the dictionary but not key1");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Dictionary1[key1] = value;
|
|
||||||
// Dictionary2[key2] = value;
|
|
||||||
|
|
||||||
// LLUDPClient[] oldArray = Array;
|
|
||||||
// int oldLength = oldArray.Length;
|
|
||||||
|
|
||||||
// LLUDPClient[] newArray = new LLUDPClient[oldLength + 1];
|
|
||||||
// for (int i = 0; i < oldLength; i++)
|
|
||||||
// newArray[i] = oldArray[i];
|
|
||||||
// newArray[oldLength] = value;
|
|
||||||
|
|
||||||
// Array = newArray;
|
|
||||||
//}
|
|
||||||
//finally { rwLock.ExitWriteLock(); }
|
|
||||||
|
|
||||||
lock (m_sync)
|
|
||||||
{
|
|
||||||
if (Dictionary1.ContainsKey(key1))
|
|
||||||
{
|
|
||||||
if (!Dictionary2.ContainsKey(key2))
|
|
||||||
throw new ArgumentException("key1 exists in the dictionary but not key2");
|
|
||||||
}
|
|
||||||
else if (Dictionary2.ContainsKey(key2))
|
|
||||||
{
|
|
||||||
if (!Dictionary1.ContainsKey(key1))
|
|
||||||
throw new ArgumentException("key2 exists in the dictionary but not key1");
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary1[key1] = value;
|
|
||||||
Dictionary2[key2] = value;
|
|
||||||
|
|
||||||
LLUDPClient[] oldArray = Array;
|
|
||||||
int oldLength = oldArray.Length;
|
|
||||||
|
|
||||||
LLUDPClient[] newArray = new LLUDPClient[oldLength + 1];
|
|
||||||
for (int i = 0; i < oldLength; i++)
|
|
||||||
newArray[i] = oldArray[i];
|
|
||||||
newArray[oldLength] = value;
|
|
||||||
|
|
||||||
Array = newArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(UUID key1, IPEndPoint key2)
|
|
||||||
{
|
|
||||||
//rwLock.EnterWriteLock();
|
|
||||||
|
|
||||||
//try
|
|
||||||
//{
|
|
||||||
// LLUDPClient value;
|
|
||||||
// if (Dictionary1.TryGetValue(key1, out value))
|
|
||||||
// {
|
|
||||||
// Dictionary1.Remove(key1);
|
|
||||||
// Dictionary2.Remove(key2);
|
|
||||||
|
|
||||||
// LLUDPClient[] oldArray = Array;
|
|
||||||
// int oldLength = oldArray.Length;
|
|
||||||
|
|
||||||
// LLUDPClient[] newArray = new LLUDPClient[oldLength - 1];
|
|
||||||
// int j = 0;
|
|
||||||
// for (int i = 0; i < oldLength; i++)
|
|
||||||
// {
|
|
||||||
// if (oldArray[i] != value)
|
|
||||||
// newArray[j++] = oldArray[i];
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Array = newArray;
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//finally { rwLock.ExitWriteLock(); }
|
|
||||||
|
|
||||||
//return false;
|
|
||||||
|
|
||||||
lock (m_sync)
|
|
||||||
{
|
|
||||||
LLUDPClient value;
|
|
||||||
if (Dictionary1.TryGetValue(key1, out value))
|
|
||||||
{
|
|
||||||
Dictionary1.Remove(key1);
|
|
||||||
Dictionary2.Remove(key2);
|
|
||||||
|
|
||||||
LLUDPClient[] oldArray = Array;
|
|
||||||
int oldLength = oldArray.Length;
|
|
||||||
|
|
||||||
LLUDPClient[] newArray = new LLUDPClient[oldLength - 1];
|
|
||||||
int j = 0;
|
|
||||||
for (int i = 0; i < oldLength; i++)
|
|
||||||
{
|
|
||||||
if (oldArray[i] != value)
|
|
||||||
newArray[j++] = oldArray[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
Array = newArray;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
//rwLock.EnterWriteLock();
|
|
||||||
|
|
||||||
//try
|
|
||||||
//{
|
|
||||||
// Dictionary1.Clear();
|
|
||||||
// Dictionary2.Clear();
|
|
||||||
// Array = new LLUDPClient[0];
|
|
||||||
//}
|
|
||||||
//finally { rwLock.ExitWriteLock(); }
|
|
||||||
|
|
||||||
lock (m_sync)
|
|
||||||
{
|
|
||||||
Dictionary1.Clear();
|
|
||||||
Dictionary2.Clear();
|
|
||||||
Array = new LLUDPClient[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get { return Array.Length; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ContainsKey(UUID key)
|
|
||||||
{
|
|
||||||
return Dictionary1.ContainsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ContainsKey(IPEndPoint key)
|
|
||||||
{
|
|
||||||
return Dictionary2.ContainsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetValue(UUID key, out LLUDPClient value)
|
|
||||||
{
|
|
||||||
////bool success;
|
|
||||||
////bool doLock = !rwLock.IsUpgradeableReadLockHeld;
|
|
||||||
////if (doLock) rwLock.EnterReadLock();
|
|
||||||
|
|
||||||
////try { success = Dictionary1.TryGetValue(key, out value); }
|
|
||||||
////finally { if (doLock) rwLock.ExitReadLock(); }
|
|
||||||
|
|
||||||
////return success;
|
|
||||||
|
|
||||||
lock (m_sync)
|
|
||||||
return Dictionary1.TryGetValue(key, out value);
|
|
||||||
|
|
||||||
//try
|
|
||||||
//{
|
|
||||||
// return Dictionary1.TryGetValue(key, out value);
|
|
||||||
//}
|
|
||||||
//catch { }
|
|
||||||
//value = null;
|
|
||||||
//return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetValue(IPEndPoint key, out LLUDPClient value)
|
|
||||||
{
|
|
||||||
////bool success;
|
|
||||||
////bool doLock = !rwLock.IsUpgradeableReadLockHeld;
|
|
||||||
////if (doLock) rwLock.EnterReadLock();
|
|
||||||
|
|
||||||
////try { success = Dictionary2.TryGetValue(key, out value); }
|
|
||||||
////finally { if (doLock) rwLock.ExitReadLock(); }
|
|
||||||
|
|
||||||
////return success;
|
|
||||||
|
|
||||||
lock (m_sync)
|
|
||||||
return Dictionary2.TryGetValue(key, out value);
|
|
||||||
|
|
||||||
//try
|
|
||||||
//{
|
|
||||||
// return Dictionary2.TryGetValue(key, out value);
|
|
||||||
//}
|
|
||||||
//catch { }
|
|
||||||
//value = null;
|
|
||||||
//return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ForEach(Action<LLUDPClient> action)
|
|
||||||
{
|
|
||||||
//bool doLock = !rwLock.IsUpgradeableReadLockHeld;
|
|
||||||
//if (doLock) rwLock.EnterUpgradeableReadLock();
|
|
||||||
|
|
||||||
//try { Parallel.ForEach<LLUDPClient>(Array, action); }
|
|
||||||
//finally { if (doLock) rwLock.ExitUpgradeableReadLock(); }
|
|
||||||
|
|
||||||
LLUDPClient[] localArray = null;
|
|
||||||
lock (m_sync)
|
|
||||||
{
|
|
||||||
localArray = new LLUDPClient[Array.Length];
|
|
||||||
Array.CopyTo(localArray, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Parallel.ForEach<LLUDPClient>(localArray, action);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -96,7 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// <summary>Incoming packets that are awaiting handling</summary>
|
/// <summary>Incoming packets that are awaiting handling</summary>
|
||||||
private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
|
private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
|
||||||
/// <summary></summary>
|
/// <summary></summary>
|
||||||
private UDPClientCollection clients = new UDPClientCollection();
|
//private UDPClientCollection m_clients = new UDPClientCollection();
|
||||||
/// <summary>Bandwidth throttle for this UDP server</summary>
|
/// <summary>Bandwidth throttle for this UDP server</summary>
|
||||||
private TokenBucket m_throttle;
|
private TokenBucket m_throttle;
|
||||||
/// <summary>Bandwidth throttle rates for this UDP server</summary>
|
/// <summary>Bandwidth throttle rates for this UDP server</summary>
|
||||||
|
@ -109,13 +109,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
private Location m_location;
|
private Location m_location;
|
||||||
/// <summary>The measured resolution of Environment.TickCount</summary>
|
/// <summary>The measured resolution of Environment.TickCount</summary>
|
||||||
private float m_tickCountResolution;
|
private float m_tickCountResolution;
|
||||||
|
/// <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>The measured resolution of Environment.TickCount</summary>
|
/// <summary>The measured resolution of Environment.TickCount</summary>
|
||||||
public float TickCountResolution { get { return m_tickCountResolution; } }
|
public float TickCountResolution { get { return m_tickCountResolution; } }
|
||||||
public Socket Server { get { return null; } }
|
public Socket Server { get { return null; } }
|
||||||
|
|
||||||
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((int)port)
|
: base(listenIP, (int)port)
|
||||||
{
|
{
|
||||||
#region Environment.TickCount Measurement
|
#region Environment.TickCount Measurement
|
||||||
|
|
||||||
|
@ -134,18 +140,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
#endregion Environment.TickCount Measurement
|
#endregion Environment.TickCount Measurement
|
||||||
|
|
||||||
m_circuitManager = circuitManager;
|
m_circuitManager = circuitManager;
|
||||||
|
int sceneThrottleBps = 0;
|
||||||
|
|
||||||
// TODO: Config support for throttling the entire connection
|
IConfig config = configSource.Configs["ClientStack.LindenUDP"];
|
||||||
m_throttle = new TokenBucket(null, 0, 0);
|
if (config != null)
|
||||||
|
{
|
||||||
|
m_asyncPacketHandling = config.GetBoolean("async_packet_handling", false);
|
||||||
|
m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0);
|
||||||
|
sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps);
|
||||||
m_throttleRates = new ThrottleRates(configSource);
|
m_throttleRates = new ThrottleRates(configSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
public new void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
if (m_scene == null)
|
if (m_scene == null)
|
||||||
throw new InvalidOperationException("Cannot LLUDPServer.Start() without an IScene reference");
|
throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference");
|
||||||
|
|
||||||
base.Start();
|
m_log.Info("[LLUDPSERVER]: Starting the LLUDP server in " + (m_asyncPacketHandling ? "asynchronous" : "synchronous") + " mode");
|
||||||
|
|
||||||
|
base.Start(m_recvBufferSize, m_asyncPacketHandling);
|
||||||
|
|
||||||
// Start the incoming packet processing thread
|
// Start the incoming packet processing thread
|
||||||
Thread incomingThread = new Thread(IncomingPacketHandler);
|
Thread incomingThread = new Thread(IncomingPacketHandler);
|
||||||
|
@ -181,24 +197,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
return x == m_location;
|
return x == m_location;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveClient(IClientAPI client)
|
|
||||||
{
|
|
||||||
m_scene.ClientManager.Remove(client.CircuitCode);
|
|
||||||
client.Close(false);
|
|
||||||
|
|
||||||
LLUDPClient udpClient;
|
|
||||||
if (clients.TryGetValue(client.AgentId, out udpClient))
|
|
||||||
{
|
|
||||||
m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + client.Name + " in " + m_scene.RegionInfo.RegionName);
|
|
||||||
udpClient.Shutdown();
|
|
||||||
clients.Remove(client.AgentId, udpClient.RemoteEndPoint);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_log.Warn("[LLUDPSERVER]: Failed to remove LLUDPClient for " + client.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
|
public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
|
||||||
{
|
{
|
||||||
// CoarseLocationUpdate packets cannot be split in an automated way
|
// CoarseLocationUpdate packets cannot be split in an automated way
|
||||||
|
@ -216,30 +214,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
for (int i = 0; i < packetCount; i++)
|
for (int i = 0; i < packetCount; i++)
|
||||||
{
|
{
|
||||||
byte[] data = datas[i];
|
byte[] data = datas[i];
|
||||||
clients.ForEach(
|
m_scene.ClientManager.ForEach(
|
||||||
delegate(LLUDPClient client)
|
delegate(IClientAPI client)
|
||||||
{ SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); });
|
{
|
||||||
|
if (client is LLClientView)
|
||||||
|
SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
byte[] data = packet.ToBytes();
|
byte[] data = packet.ToBytes();
|
||||||
clients.ForEach(
|
m_scene.ClientManager.ForEach(
|
||||||
delegate(LLUDPClient client)
|
delegate(IClientAPI client)
|
||||||
{ SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendPacket(UUID agentID, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
|
|
||||||
{
|
{
|
||||||
LLUDPClient client;
|
if (client is LLClientView)
|
||||||
if (clients.TryGetValue(agentID, out client))
|
SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category);
|
||||||
SendPacket(client, packet, category, allowSplitting);
|
}
|
||||||
else
|
);
|
||||||
m_log.Warn("[LLUDPSERVER]: Attempted to send a packet to unknown agentID " + agentID);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendPacket(LLUDPClient client, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
|
public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
|
||||||
{
|
{
|
||||||
// CoarseLocationUpdate packets cannot be split in an automated way
|
// CoarseLocationUpdate packets cannot be split in an automated way
|
||||||
if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
|
if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
|
||||||
|
@ -256,25 +253,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
for (int i = 0; i < packetCount; i++)
|
for (int i = 0; i < packetCount; i++)
|
||||||
{
|
{
|
||||||
byte[] data = datas[i];
|
byte[] data = datas[i];
|
||||||
SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category);
|
SendPacketData(udpClient, data, packet.Type, category);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
byte[] data = packet.ToBytes();
|
byte[] data = packet.ToBytes();
|
||||||
SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category);
|
SendPacketData(udpClient, data, packet.Type, category);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendPacketData(LLUDPClient client, byte[] data, int dataLength, PacketType type, bool doZerocode, ThrottleOutPacketType category)
|
public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category)
|
||||||
{
|
{
|
||||||
|
int dataLength = data.Length;
|
||||||
|
bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
|
||||||
|
|
||||||
// Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum.
|
// Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum.
|
||||||
// The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting
|
// The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting
|
||||||
// there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here
|
// there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here
|
||||||
// to accomodate for both common scenarios and provide ample room for ACK appending in both
|
// to accomodate for both common scenarios and provide ample room for ACK appending in both
|
||||||
int bufferSize = (dataLength > 180) ? Packet.MTU : 200;
|
int bufferSize = (dataLength > 180) ? Packet.MTU : 200;
|
||||||
|
|
||||||
UDPPacketBuffer buffer = new UDPPacketBuffer(client.RemoteEndPoint, bufferSize);
|
UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
|
||||||
|
|
||||||
// Zerocode if needed
|
// Zerocode if needed
|
||||||
if (doZerocode)
|
if (doZerocode)
|
||||||
|
@ -285,17 +285,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
// The packet grew larger than the bufferSize while zerocoding.
|
// The packet grew larger than the bufferSize while zerocoding.
|
||||||
// Remove the MSG_ZEROCODED flag and send the unencoded data
|
// Remove the MSG_ZEROCODED flag and send the unencoded data
|
||||||
// instead
|
// instead
|
||||||
m_log.Info("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding. Removing MSG_ZEROCODED flag");
|
m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". Removing MSG_ZEROCODED flag");
|
||||||
data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
|
data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
|
||||||
//
|
|
||||||
buffer = new UDPPacketBuffer(client.RemoteEndPoint, dataLength);
|
|
||||||
//
|
|
||||||
Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
|
Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// ??? will it fit?
|
|
||||||
Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
|
Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
|
||||||
}
|
}
|
||||||
buffer.DataLength = dataLength;
|
buffer.DataLength = dataLength;
|
||||||
|
@ -303,7 +299,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
#region Queue or Send
|
#region Queue or Send
|
||||||
|
|
||||||
// Look up the UDPClient this is going to
|
// Look up the UDPClient this is going to
|
||||||
OutgoingPacket outgoingPacket = new OutgoingPacket(client, buffer, category);
|
OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category);
|
||||||
|
|
||||||
if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
|
if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
|
||||||
SendPacketFinal(outgoingPacket);
|
SendPacketFinal(outgoingPacket);
|
||||||
|
@ -311,18 +307,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
#endregion Queue or Send
|
#endregion Queue or Send
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendAcks(LLUDPClient client)
|
public void SendAcks(LLUDPClient udpClient)
|
||||||
{
|
{
|
||||||
uint ack;
|
uint ack;
|
||||||
|
|
||||||
if (client.PendingAcks.Dequeue(out ack))
|
if (udpClient.PendingAcks.Dequeue(out ack))
|
||||||
{
|
{
|
||||||
List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
|
List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
|
||||||
PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock();
|
PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock();
|
||||||
block.ID = ack;
|
block.ID = ack;
|
||||||
blocks.Add(block);
|
blocks.Add(block);
|
||||||
|
|
||||||
while (client.PendingAcks.Dequeue(out ack))
|
while (udpClient.PendingAcks.Dequeue(out ack))
|
||||||
{
|
{
|
||||||
block = new PacketAckPacket.PacketsBlock();
|
block = new PacketAckPacket.PacketsBlock();
|
||||||
block.ID = ack;
|
block.ID = ack;
|
||||||
|
@ -333,22 +329,39 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
packet.Header.Reliable = false;
|
packet.Header.Reliable = false;
|
||||||
packet.Packets = blocks.ToArray();
|
packet.Packets = blocks.ToArray();
|
||||||
|
|
||||||
SendPacket(client, packet, ThrottleOutPacketType.Unknown, true);
|
SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendPing(LLUDPClient client)
|
public void SendPing(LLUDPClient udpClient)
|
||||||
{
|
{
|
||||||
IClientAPI api = client.ClientAPI;
|
StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
|
||||||
if (api != null)
|
pc.Header.Reliable = false;
|
||||||
api.SendStartPingCheck(client.CurrentPingSequence++);
|
|
||||||
|
OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest();
|
||||||
|
|
||||||
|
pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++;
|
||||||
|
pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0;
|
||||||
|
|
||||||
|
SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResendUnacked(LLUDPClient client)
|
public void ResendUnacked(LLUDPClient udpClient)
|
||||||
{
|
{
|
||||||
if (client.NeedAcks.Count > 0)
|
if (udpClient.IsConnected && udpClient.NeedAcks.Count > 0)
|
||||||
{
|
{
|
||||||
List<OutgoingPacket> expiredPackets = client.NeedAcks.GetExpiredPackets(client.RTO);
|
// Disconnect an agent if no packets are received for some time
|
||||||
|
//FIXME: Make 60 an .ini setting
|
||||||
|
if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60)
|
||||||
|
{
|
||||||
|
m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID);
|
||||||
|
|
||||||
|
RemoveClient(udpClient);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO
|
||||||
|
List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
|
||||||
|
|
||||||
if (expiredPackets != null)
|
if (expiredPackets != null)
|
||||||
{
|
{
|
||||||
|
@ -357,11 +370,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
OutgoingPacket outgoingPacket = expiredPackets[i];
|
OutgoingPacket outgoingPacket = expiredPackets[i];
|
||||||
|
|
||||||
// FIXME: Make this an .ini setting
|
//m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
|
||||||
if (outgoingPacket.ResendCount < 3)
|
// outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
|
||||||
{
|
|
||||||
//Logger.Debug(String.Format("Resending packet #{0} (attempt {1}), {2}ms have passed",
|
|
||||||
// outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount));
|
|
||||||
|
|
||||||
// Set the resent flag
|
// Set the resent flag
|
||||||
outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
|
outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
|
||||||
|
@ -375,36 +385,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
Interlocked.Increment(ref outgoingPacket.ResendCount);
|
Interlocked.Increment(ref outgoingPacket.ResendCount);
|
||||||
//Interlocked.Increment(ref Stats.ResentPackets);
|
//Interlocked.Increment(ref Stats.ResentPackets);
|
||||||
|
|
||||||
// Queue or (re)send the packet
|
// Requeue or resend the packet
|
||||||
if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
|
if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
|
||||||
SendPacketFinal(outgoingPacket);
|
SendPacketFinal(outgoingPacket);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
m_log.DebugFormat("[LLUDPSERVER]: Dropping packet #{0} for agent {1} after {2} failed attempts",
|
|
||||||
outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount);
|
|
||||||
|
|
||||||
lock (client.NeedAcks.SyncRoot)
|
|
||||||
client.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber);
|
|
||||||
|
|
||||||
//Interlocked.Increment(ref Stats.DroppedPackets);
|
|
||||||
|
|
||||||
// Disconnect an agent if no packets are received for some time
|
|
||||||
//FIXME: Make 60 an .ini setting
|
|
||||||
if (Environment.TickCount - client.TickLastPacketReceived > 1000 * 60)
|
|
||||||
{
|
|
||||||
m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + client.ClientAPI.Name);
|
|
||||||
|
|
||||||
RemoveClient(client.ClientAPI);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Flush()
|
public void Flush(LLUDPClient udpClient)
|
||||||
{
|
{
|
||||||
// FIXME: Implement?
|
// FIXME: Implement?
|
||||||
}
|
}
|
||||||
|
@ -415,7 +404,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
byte flags = buffer.Data[0];
|
byte flags = buffer.Data[0];
|
||||||
bool isResend = (flags & Helpers.MSG_RESENT) != 0;
|
bool isResend = (flags & Helpers.MSG_RESENT) != 0;
|
||||||
bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;
|
bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;
|
||||||
LLUDPClient client = outgoingPacket.Client;
|
LLUDPClient udpClient = outgoingPacket.Client;
|
||||||
|
|
||||||
|
if (!udpClient.IsConnected)
|
||||||
|
return;
|
||||||
|
|
||||||
// Keep track of when this packet was sent out (right now)
|
// Keep track of when this packet was sent out (right now)
|
||||||
outgoingPacket.TickCount = Environment.TickCount;
|
outgoingPacket.TickCount = Environment.TickCount;
|
||||||
|
@ -424,11 +416,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
int dataLength = buffer.DataLength;
|
int dataLength = buffer.DataLength;
|
||||||
|
|
||||||
// Keep appending ACKs until there is no room left in the packet or there are
|
// Keep appending ACKs until there is no room left in the buffer or there are
|
||||||
// no more ACKs to append
|
// no more ACKs to append
|
||||||
uint ackCount = 0;
|
uint ackCount = 0;
|
||||||
uint ack;
|
uint ack;
|
||||||
while (dataLength + 5 < buffer.Data.Length && client.PendingAcks.Dequeue(out ack))
|
while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack))
|
||||||
{
|
{
|
||||||
Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
|
Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
|
||||||
dataLength += 4;
|
dataLength += 4;
|
||||||
|
@ -447,24 +439,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
#endregion ACK Appending
|
#endregion ACK Appending
|
||||||
|
|
||||||
|
#region Sequence Number Assignment
|
||||||
|
|
||||||
if (!isResend)
|
if (!isResend)
|
||||||
{
|
{
|
||||||
// Not a resend, assign a new sequence number
|
// Not a resend, assign a new sequence number
|
||||||
uint sequenceNumber = (uint)Interlocked.Increment(ref client.CurrentSequence);
|
uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence);
|
||||||
Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
|
Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
|
||||||
outgoingPacket.SequenceNumber = sequenceNumber;
|
outgoingPacket.SequenceNumber = sequenceNumber;
|
||||||
|
|
||||||
if (isReliable)
|
if (isReliable)
|
||||||
{
|
{
|
||||||
// Add this packet to the list of ACK responses we are waiting on from the server
|
// Add this packet to the list of ACK responses we are waiting on from the server
|
||||||
client.NeedAcks.Add(outgoingPacket);
|
udpClient.NeedAcks.Add(outgoingPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion Sequence Number Assignment
|
||||||
|
|
||||||
// Stats tracking
|
// Stats tracking
|
||||||
Interlocked.Increment(ref client.PacketsSent);
|
Interlocked.Increment(ref udpClient.PacketsSent);
|
||||||
if (isReliable)
|
if (isReliable)
|
||||||
Interlocked.Add(ref client.UnackedBytes, outgoingPacket.Buffer.DataLength);
|
Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength);
|
||||||
|
|
||||||
// Put the UDP payload on the wire
|
// Put the UDP payload on the wire
|
||||||
AsyncBeginSend(buffer);
|
AsyncBeginSend(buffer);
|
||||||
|
@ -473,10 +469,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
protected override void PacketReceived(UDPPacketBuffer buffer)
|
protected override void PacketReceived(UDPPacketBuffer buffer)
|
||||||
{
|
{
|
||||||
// Debugging/Profiling
|
// Debugging/Profiling
|
||||||
//try { Thread.CurrentThread.Name = "PacketReceived (" + scene.RegionName + ")"; }
|
//try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; }
|
||||||
//catch (Exception) { }
|
//catch (Exception) { }
|
||||||
|
|
||||||
LLUDPClient client = null;
|
LLUDPClient udpClient = null;
|
||||||
Packet packet = null;
|
Packet packet = null;
|
||||||
int packetEnd = buffer.DataLength - 1;
|
int packetEnd = buffer.DataLength - 1;
|
||||||
IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint;
|
IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint;
|
||||||
|
@ -491,61 +487,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
catch (MalformedDataException)
|
catch (MalformedDataException)
|
||||||
{
|
{
|
||||||
m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet:\n{0}",
|
m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet from {0}:\n{1}",
|
||||||
Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
|
buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fail-safe check
|
// Fail-safe check
|
||||||
if (packet == null)
|
if (packet == null)
|
||||||
{
|
{
|
||||||
m_log.Warn("[LLUDPSERVER]: Couldn't build a message from the incoming data");
|
m_log.Warn("[LLUDPSERVER]: Couldn't build a message from incoming data " + buffer.DataLength +
|
||||||
|
" bytes long from " + buffer.RemoteEndPoint);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Stats.RecvBytes += (ulong)buffer.DataLength;
|
|
||||||
//++Stats.RecvPackets;
|
|
||||||
|
|
||||||
#endregion Decoding
|
#endregion Decoding
|
||||||
|
|
||||||
#region UseCircuitCode Handling
|
#region Packet to Client Mapping
|
||||||
|
|
||||||
|
// UseCircuitCode handling
|
||||||
if (packet.Type == PacketType.UseCircuitCode)
|
if (packet.Type == PacketType.UseCircuitCode)
|
||||||
{
|
{
|
||||||
UseCircuitCodePacket useCircuitCode = (UseCircuitCodePacket)packet;
|
AddNewClient((UseCircuitCodePacket)packet, (IPEndPoint)buffer.RemoteEndPoint);
|
||||||
IClientAPI newuser;
|
|
||||||
uint circuitCode = useCircuitCode.CircuitCode.Code;
|
|
||||||
|
|
||||||
// Check if the client is already established
|
|
||||||
if (!m_scene.ClientManager.TryGetClient(circuitCode, out newuser))
|
|
||||||
{
|
|
||||||
AddNewClient(useCircuitCode, (IPEndPoint)buffer.RemoteEndPoint);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine which agent this packet came from
|
// Determine which agent this packet came from
|
||||||
if (!clients.TryGetValue(address, out client))
|
IClientAPI client;
|
||||||
|
if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView))
|
||||||
{
|
{
|
||||||
m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
|
m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address +
|
||||||
|
" in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion UseCircuitCode Handling
|
udpClient = ((LLClientView)client).UDPClient;
|
||||||
|
|
||||||
|
if (!udpClient.IsConnected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#endregion Packet to Client Mapping
|
||||||
|
|
||||||
// Stats tracking
|
// Stats tracking
|
||||||
Interlocked.Increment(ref client.PacketsReceived);
|
Interlocked.Increment(ref udpClient.PacketsReceived);
|
||||||
|
|
||||||
#region ACK Receiving
|
#region ACK Receiving
|
||||||
|
|
||||||
int now = Environment.TickCount;
|
int now = Environment.TickCount;
|
||||||
client.TickLastPacketReceived = now;
|
udpClient.TickLastPacketReceived = now;
|
||||||
|
|
||||||
// Handle appended ACKs
|
// Handle appended ACKs
|
||||||
if (packet.Header.AppendedAcks && packet.Header.AckList != null)
|
if (packet.Header.AppendedAcks && packet.Header.AckList != null)
|
||||||
{
|
{
|
||||||
lock (client.NeedAcks.SyncRoot)
|
lock (udpClient.NeedAcks.SyncRoot)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < packet.Header.AckList.Length; i++)
|
for (int i = 0; i < packet.Header.AckList.Length; i++)
|
||||||
AcknowledgePacket(client, packet.Header.AckList[i], now, packet.Header.Resent);
|
AcknowledgePacket(udpClient, packet.Header.AckList[i], now, packet.Header.Resent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,10 +548,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
PacketAckPacket ackPacket = (PacketAckPacket)packet;
|
PacketAckPacket ackPacket = (PacketAckPacket)packet;
|
||||||
|
|
||||||
lock (client.NeedAcks.SyncRoot)
|
lock (udpClient.NeedAcks.SyncRoot)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < ackPacket.Packets.Length; i++)
|
for (int i = 0; i < ackPacket.Packets.Length; i++)
|
||||||
AcknowledgePacket(client, ackPacket.Packets[i].ID, now, packet.Header.Resent);
|
AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,27 +560,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
#region ACK Sending
|
#region ACK Sending
|
||||||
|
|
||||||
if (packet.Header.Reliable)
|
if (packet.Header.Reliable)
|
||||||
client.PendingAcks.Enqueue((uint)packet.Header.Sequence);
|
udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
|
||||||
|
|
||||||
// This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
|
// This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
|
||||||
// add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
|
// add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
|
||||||
// 2*MTU bytes from the value and send ACKs, and finally add the local value back to
|
// 2*MTU bytes from the value and send ACKs, and finally add the local value back to
|
||||||
// client.BytesSinceLastACK. Lockless thread safety
|
// client.BytesSinceLastACK. Lockless thread safety
|
||||||
int bytesSinceLastACK = Interlocked.Exchange(ref client.BytesSinceLastACK, 0);
|
int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
|
||||||
bytesSinceLastACK += buffer.DataLength;
|
bytesSinceLastACK += buffer.DataLength;
|
||||||
if (bytesSinceLastACK > Packet.MTU * 2)
|
if (bytesSinceLastACK > Packet.MTU * 2)
|
||||||
{
|
{
|
||||||
bytesSinceLastACK -= Packet.MTU * 2;
|
bytesSinceLastACK -= Packet.MTU * 2;
|
||||||
SendAcks(client);
|
SendAcks(udpClient);
|
||||||
}
|
}
|
||||||
Interlocked.Add(ref client.BytesSinceLastACK, bytesSinceLastACK);
|
Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
|
||||||
|
|
||||||
#endregion ACK Sending
|
#endregion ACK Sending
|
||||||
|
|
||||||
#region Incoming Packet Accounting
|
#region Incoming Packet Accounting
|
||||||
|
|
||||||
// Check the archive of received reliable packet IDs to see whether we already received this packet
|
// Check the archive of received reliable packet IDs to see whether we already received this packet
|
||||||
if (packet.Header.Reliable && !client.PacketArchive.TryEnqueue(packet.Header.Sequence))
|
if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
|
||||||
{
|
{
|
||||||
if (packet.Header.Resent)
|
if (packet.Header.Resent)
|
||||||
m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type);
|
m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type);
|
||||||
|
@ -603,7 +597,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
if (packet.Type != PacketType.PacketAck)
|
if (packet.Type != PacketType.PacketAck)
|
||||||
{
|
{
|
||||||
// Inbox insertion
|
// Inbox insertion
|
||||||
packetInbox.Enqueue(new IncomingPacket(client, packet));
|
packetInbox.Enqueue(new IncomingPacket(udpClient, packet));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -622,54 +616,60 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint)
|
private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint)
|
||||||
{
|
|
||||||
//Slave regions don't accept new clients
|
|
||||||
if (m_scene.RegionStatus != RegionStatus.SlaveScene)
|
|
||||||
{
|
|
||||||
AuthenticateResponse sessionInfo;
|
|
||||||
bool isNewCircuit = !clients.ContainsKey(remoteEndPoint);
|
|
||||||
|
|
||||||
if (!IsClientAuthorized(useCircuitCode, out sessionInfo))
|
|
||||||
{
|
|
||||||
m_log.WarnFormat(
|
|
||||||
"[CONNECTION FAILURE]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
|
|
||||||
useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNewCircuit)
|
|
||||||
{
|
{
|
||||||
UUID agentID = useCircuitCode.CircuitCode.ID;
|
UUID agentID = useCircuitCode.CircuitCode.ID;
|
||||||
UUID sessionID = useCircuitCode.CircuitCode.SessionID;
|
UUID sessionID = useCircuitCode.CircuitCode.SessionID;
|
||||||
uint circuitCode = useCircuitCode.CircuitCode.Code;
|
uint circuitCode = useCircuitCode.CircuitCode.Code;
|
||||||
|
|
||||||
|
if (m_scene.RegionStatus != RegionStatus.SlaveScene)
|
||||||
|
{
|
||||||
|
AuthenticateResponse sessionInfo;
|
||||||
|
if (IsClientAuthorized(useCircuitCode, out sessionInfo))
|
||||||
|
{
|
||||||
AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo);
|
AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Don't create circuits for unauthorized clients
|
||||||
|
m_log.WarnFormat(
|
||||||
|
"[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
|
||||||
|
useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Slave regions don't accept new clients
|
||||||
|
m_log.Debug("[LLUDPSERVER]: Slave region " + m_scene.RegionInfo.RegionName + " ignoring UseCircuitCode packet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
|
private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
|
||||||
{
|
{
|
||||||
// Create the LLUDPClient
|
// Create the LLUDPClient
|
||||||
LLUDPClient client = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint);
|
LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint);
|
||||||
|
|
||||||
|
if (!m_scene.ClientManager.ContainsKey(agentID))
|
||||||
|
{
|
||||||
// Create the LLClientView
|
// Create the LLClientView
|
||||||
LLClientView clientApi = new LLClientView(remoteEndPoint, m_scene, this, client, sessionInfo, agentID, sessionID, circuitCode);
|
LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
|
||||||
clientApi.OnViewerEffect += m_scene.ClientManager.ViewerEffectHandler;
|
client.OnLogout += LogoutHandler;
|
||||||
clientApi.OnLogout += LogoutHandler;
|
|
||||||
clientApi.OnConnectionClosed += RemoveClient;
|
|
||||||
|
|
||||||
// Start the IClientAPI
|
// Start the IClientAPI
|
||||||
m_scene.ClientManager.Add(circuitCode, clientApi);
|
client.Start();
|
||||||
clientApi.Start();
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}",
|
||||||
|
udpClient.AgentID, remoteEndPoint, circuitCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Give LLUDPClient a reference to IClientAPI
|
private void RemoveClient(LLUDPClient udpClient)
|
||||||
client.ClientAPI = clientApi;
|
{
|
||||||
|
// Remove this client from the scene
|
||||||
// Add the new client to our list of tracked clients
|
IClientAPI client;
|
||||||
clients.Add(agentID, client.RemoteEndPoint, client);
|
if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client))
|
||||||
|
client.Close();
|
||||||
m_log.DebugFormat("[LLUDPSERVER]: Added new client {0} to region {1}", agentID, m_scene.RegionInfo.RegionName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend)
|
private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend)
|
||||||
|
@ -747,20 +747,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
elapsed500MS = 0;
|
elapsed500MS = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
clients.ForEach(
|
m_scene.ClientManager.ForEach(
|
||||||
delegate(LLUDPClient client)
|
delegate(IClientAPI client)
|
||||||
{
|
{
|
||||||
if (client.DequeueOutgoing())
|
if (client is LLClientView)
|
||||||
|
{
|
||||||
|
LLUDPClient udpClient = ((LLClientView)client).UDPClient;
|
||||||
|
|
||||||
|
if (udpClient.IsConnected)
|
||||||
|
{
|
||||||
|
if (udpClient.DequeueOutgoing())
|
||||||
packetSent = true;
|
packetSent = true;
|
||||||
if (resendUnacked)
|
if (resendUnacked)
|
||||||
ResendUnacked(client);
|
ResendUnacked(udpClient);
|
||||||
if (sendAcks)
|
if (sendAcks)
|
||||||
{
|
{
|
||||||
SendAcks(client);
|
SendAcks(udpClient);
|
||||||
client.SendPacketStats();
|
udpClient.SendPacketStats();
|
||||||
}
|
}
|
||||||
if (sendPings)
|
if (sendPings)
|
||||||
SendPing(client);
|
SendPing(udpClient);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -773,19 +781,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
IncomingPacket incomingPacket = (IncomingPacket)state;
|
IncomingPacket incomingPacket = (IncomingPacket)state;
|
||||||
Packet packet = incomingPacket.Packet;
|
Packet packet = incomingPacket.Packet;
|
||||||
LLUDPClient client = incomingPacket.Client;
|
LLUDPClient udpClient = incomingPacket.Client;
|
||||||
|
IClientAPI client;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (packet == null || client == null || client.ClientAPI == null)
|
if (packet == null || udpClient == null)
|
||||||
{
|
{
|
||||||
m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", Client=\"{1}\", Client.ClientAPI=\"{2}\"",
|
m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"",
|
||||||
packet, client, (client != null) ? client.ClientAPI : null);
|
packet, udpClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure this client is still alive
|
||||||
|
if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client))
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Process this packet
|
// Process this packet
|
||||||
client.ClientAPI.ProcessInPacket(packet);
|
client.ProcessInPacket(packet);
|
||||||
}
|
}
|
||||||
catch (ThreadAbortException)
|
catch (ThreadAbortException)
|
||||||
{
|
{
|
||||||
|
@ -796,15 +808,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
// Don't let a failure in an individual client thread crash the whole sim.
|
// Don't let a failure in an individual client thread crash the whole sim.
|
||||||
m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", client.AgentID, packet.Type);
|
m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type);
|
||||||
m_log.Error(e.Message, e);
|
m_log.Error(e.Message, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void LogoutHandler(IClientAPI client)
|
private void LogoutHandler(IClientAPI client)
|
||||||
{
|
{
|
||||||
client.SendLogoutPacket();
|
client.SendLogoutPacket();
|
||||||
RemoveClient(client);
|
if (client.IsActive)
|
||||||
|
RemoveClient(((LLClientView)client).UDPClient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,419 +1,137 @@
|
||||||
//--------- Modified Version -------------------
|
/*
|
||||||
///*
|
* Copyright (c) 2006, Clutch, Inc.
|
||||||
// * Copyright (c) 2006, Clutch, Inc.
|
* Original Author: Jeff Cesnik
|
||||||
// * Original Author: Jeff Cesnik
|
* All rights reserved.
|
||||||
// * All rights reserved.
|
*
|
||||||
// *
|
* - Redistribution and use in source and binary forms, with or without
|
||||||
// * - Redistribution and use in source and binary forms, with or without
|
* modification, are permitted provided that the following conditions are met:
|
||||||
// * modification, are permitted provided that the following conditions are met:
|
*
|
||||||
// *
|
* - Redistributions of source code must retain the above copyright notice, this
|
||||||
// * - Redistributions of source code must retain the above copyright notice, this
|
* list of conditions and the following disclaimer.
|
||||||
// * list of conditions and the following disclaimer.
|
* - Neither the name of the openmetaverse.org nor the names
|
||||||
// * - Neither the name of the openmetaverse.org nor the names
|
* of its contributors may be used to endorse or promote products derived from
|
||||||
// * of its contributors may be used to endorse or promote products derived from
|
* this software without specific prior written permission.
|
||||||
// * this software without specific prior written permission.
|
*
|
||||||
// *
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
// * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
// * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
// * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
// * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
// * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
// * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
// * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
// * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
// * 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
|
||||||
// * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
// * POSSIBILITY OF SUCH DAMAGE.
|
*/
|
||||||
// */
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using OpenMetaverse;
|
using log4net;
|
||||||
|
|
||||||
//namespace OpenSim.Region.ClientStack.LindenUDP
|
namespace OpenMetaverse
|
||||||
//{
|
|
||||||
// /// <summary>
|
|
||||||
// ///
|
|
||||||
// /// </summary>
|
|
||||||
// public abstract class OpenSimUDPBase
|
|
||||||
// {
|
|
||||||
// // these abstract methods must be implemented in a derived class to actually do
|
|
||||||
// // something with the packets that are sent and received.
|
|
||||||
// protected abstract void PacketReceived(UDPPacketBuffer buffer);
|
|
||||||
// protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent);
|
|
||||||
|
|
||||||
// // the port to listen on
|
|
||||||
// internal int udpPort;
|
|
||||||
|
|
||||||
// // the UDP socket
|
|
||||||
// private Socket udpSocket;
|
|
||||||
|
|
||||||
// // the ReaderWriterLock is used solely for the purposes of shutdown (Stop()).
|
|
||||||
// // since there are potentially many "reader" threads in the internal .NET IOCP
|
|
||||||
// // thread pool, this is a cheaper synchronization primitive than using
|
|
||||||
// // a Mutex object. This allows many UDP socket "reads" concurrently - when
|
|
||||||
// // Stop() is called, it attempts to obtain a writer lock which will then
|
|
||||||
// // wait until all outstanding operations are completed before shutting down.
|
|
||||||
// // this avoids the problem of closing the socket with outstanding operations
|
|
||||||
// // and trying to catch the inevitable ObjectDisposedException.
|
|
||||||
// private ReaderWriterLock rwLock = new ReaderWriterLock();
|
|
||||||
|
|
||||||
// // number of outstanding operations. This is a reference count
|
|
||||||
// // which we use to ensure that the threads exit cleanly. Note that
|
|
||||||
// // we need this because the threads will potentially still need to process
|
|
||||||
// // data even after the socket is closed.
|
|
||||||
// private int rwOperationCount = 0;
|
|
||||||
|
|
||||||
// // the all important shutdownFlag. This is synchronized through the ReaderWriterLock.
|
|
||||||
// private volatile bool shutdownFlag = true;
|
|
||||||
|
|
||||||
// // the remote endpoint to communicate with
|
|
||||||
// protected IPEndPoint remoteEndPoint = null;
|
|
||||||
|
|
||||||
|
|
||||||
// /// <summary>
|
|
||||||
// /// Initialize the UDP packet handler in server mode
|
|
||||||
// /// </summary>
|
|
||||||
// /// <param name="port">Port to listening for incoming UDP packets on</param>
|
|
||||||
// public OpenSimUDPBase(int port)
|
|
||||||
// {
|
|
||||||
// udpPort = port;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// <summary>
|
|
||||||
// /// Initialize the UDP packet handler in client mode
|
|
||||||
// /// </summary>
|
|
||||||
// /// <param name="endPoint">Remote UDP server to connect to</param>
|
|
||||||
// public OpenSimUDPBase(IPEndPoint endPoint)
|
|
||||||
// {
|
|
||||||
// remoteEndPoint = endPoint;
|
|
||||||
// udpPort = 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// <summary>
|
|
||||||
// ///
|
|
||||||
// /// </summary>
|
|
||||||
// public void Start()
|
|
||||||
// {
|
|
||||||
// if (shutdownFlag)
|
|
||||||
// {
|
|
||||||
// if (remoteEndPoint == null)
|
|
||||||
// {
|
|
||||||
// // Server mode
|
|
||||||
|
|
||||||
// // create and bind the socket
|
|
||||||
// IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort);
|
|
||||||
// udpSocket = new Socket(
|
|
||||||
// AddressFamily.InterNetwork,
|
|
||||||
// SocketType.Dgram,
|
|
||||||
// ProtocolType.Udp);
|
|
||||||
// udpSocket.Bind(ipep);
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// // Client mode
|
|
||||||
// IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort);
|
|
||||||
// udpSocket = new Socket(
|
|
||||||
// AddressFamily.InterNetwork,
|
|
||||||
// SocketType.Dgram,
|
|
||||||
// ProtocolType.Udp);
|
|
||||||
// udpSocket.Bind(ipep);
|
|
||||||
// //udpSocket.Connect(remoteEndPoint);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // we're not shutting down, we're starting up
|
|
||||||
// shutdownFlag = false;
|
|
||||||
|
|
||||||
// // kick off an async receive. The Start() method will return, the
|
|
||||||
// // actual receives will occur asynchronously and will be caught in
|
|
||||||
// // AsyncEndRecieve().
|
|
||||||
// AsyncBeginReceive();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// <summary>
|
|
||||||
// ///
|
|
||||||
// /// </summary>
|
|
||||||
// public void Stop()
|
|
||||||
// {
|
|
||||||
// if (!shutdownFlag)
|
|
||||||
// {
|
|
||||||
// // 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 that the socket is closed.
|
|
||||||
// rwLock.AcquireWriterLock(-1);
|
|
||||||
// shutdownFlag = true;
|
|
||||||
// udpSocket.Close();
|
|
||||||
// rwLock.ReleaseWriterLock();
|
|
||||||
|
|
||||||
// // wait for any pending operations to complete on other
|
|
||||||
// // threads before exiting.
|
|
||||||
// const int FORCE_STOP = 100;
|
|
||||||
// int i = 0;
|
|
||||||
// while (rwOperationCount > 0 && i < FORCE_STOP)
|
|
||||||
// {
|
|
||||||
// Thread.Sleep(10);
|
|
||||||
// ++i;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (i >= FORCE_STOP)
|
|
||||||
// {
|
|
||||||
// Logger.Log("UDPBase.Stop() forced shutdown while waiting on pending operations",
|
|
||||||
// Helpers.LogLevel.Warning);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// <summary>
|
|
||||||
// ///
|
|
||||||
// /// </summary>
|
|
||||||
// public bool IsRunning
|
|
||||||
// {
|
|
||||||
// get { return !shutdownFlag; }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private void AsyncBeginReceive()
|
|
||||||
// {
|
|
||||||
// // this method actually kicks off the async read on the socket.
|
|
||||||
// // we aquire a reader lock here to ensure that no other thread
|
|
||||||
// // is trying to set shutdownFlag and close the socket.
|
|
||||||
// rwLock.AcquireReaderLock(-1);
|
|
||||||
|
|
||||||
// if (!shutdownFlag)
|
|
||||||
// {
|
|
||||||
// // increment the count of pending operations
|
|
||||||
// Interlocked.Increment(ref rwOperationCount);
|
|
||||||
|
|
||||||
// // allocate a packet buffer
|
|
||||||
// //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut();
|
|
||||||
// UDPPacketBuffer buf = new UDPPacketBuffer();
|
|
||||||
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// // kick off an async read
|
|
||||||
// udpSocket.BeginReceiveFrom(
|
|
||||||
// //wrappedBuffer.Instance.Data,
|
|
||||||
// buf.Data,
|
|
||||||
// 0,
|
|
||||||
// UDPPacketBuffer.BUFFER_SIZE,
|
|
||||||
// SocketFlags.None,
|
|
||||||
// //ref wrappedBuffer.Instance.RemoteEndPoint,
|
|
||||||
// ref buf.RemoteEndPoint,
|
|
||||||
// new AsyncCallback(AsyncEndReceive),
|
|
||||||
// //wrappedBuffer);
|
|
||||||
// buf);
|
|
||||||
// }
|
|
||||||
// catch (SocketException)
|
|
||||||
// {
|
|
||||||
// // something bad happened
|
|
||||||
// //Logger.Log(
|
|
||||||
// // "A SocketException occurred in UDPServer.AsyncBeginReceive()",
|
|
||||||
// // Helpers.LogLevel.Error, se);
|
|
||||||
|
|
||||||
// // an error occurred, therefore the operation is void. Decrement the reference count.
|
|
||||||
// Interlocked.Decrement(ref rwOperationCount);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // we're done with the socket for now, release the reader lock.
|
|
||||||
// rwLock.ReleaseReaderLock();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private void AsyncEndReceive(IAsyncResult iar)
|
|
||||||
// {
|
|
||||||
// // Asynchronous receive operations will complete here through the call
|
|
||||||
// // to AsyncBeginReceive
|
|
||||||
|
|
||||||
// // aquire a reader lock
|
|
||||||
// rwLock.AcquireReaderLock(-1);
|
|
||||||
|
|
||||||
// if (!shutdownFlag)
|
|
||||||
// {
|
|
||||||
// // 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
|
|
||||||
// {
|
|
||||||
// // get the length of data actually read from the socket, store it with the
|
|
||||||
// // buffer
|
|
||||||
// buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
|
|
||||||
|
|
||||||
// // this operation is now complete, decrement the reference count
|
|
||||||
// Interlocked.Decrement(ref rwOperationCount);
|
|
||||||
|
|
||||||
// // we're done with the socket, release the reader lock
|
|
||||||
// rwLock.ReleaseReaderLock();
|
|
||||||
|
|
||||||
// // call the abstract method PacketReceived(), passing the buffer that
|
|
||||||
// // has just been filled from the socket read.
|
|
||||||
// PacketReceived(buffer);
|
|
||||||
// }
|
|
||||||
// catch (SocketException)
|
|
||||||
// {
|
|
||||||
// // an error occurred, therefore the operation is void. Decrement the reference count.
|
|
||||||
// Interlocked.Decrement(ref rwOperationCount);
|
|
||||||
|
|
||||||
// // we're done with the socket for now, release the reader lock.
|
|
||||||
// rwLock.ReleaseReaderLock();
|
|
||||||
// }
|
|
||||||
// finally
|
|
||||||
// {
|
|
||||||
// // start another receive - this keeps the server going!
|
|
||||||
// AsyncBeginReceive();
|
|
||||||
|
|
||||||
// //wrappedBuffer.Dispose();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// // nothing bad happened, but we are done with the operation
|
|
||||||
// // decrement the reference count and release the reader lock
|
|
||||||
// Interlocked.Decrement(ref rwOperationCount);
|
|
||||||
// rwLock.ReleaseReaderLock();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public void AsyncBeginSend(UDPPacketBuffer buf)
|
|
||||||
// {
|
|
||||||
// rwLock.AcquireReaderLock(-1);
|
|
||||||
|
|
||||||
// if (!shutdownFlag)
|
|
||||||
// {
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// Interlocked.Increment(ref rwOperationCount);
|
|
||||||
// udpSocket.BeginSendTo(
|
|
||||||
// buf.Data,
|
|
||||||
// 0,
|
|
||||||
// buf.DataLength,
|
|
||||||
// SocketFlags.None,
|
|
||||||
// buf.RemoteEndPoint,
|
|
||||||
// new AsyncCallback(AsyncEndSend),
|
|
||||||
// buf);
|
|
||||||
// }
|
|
||||||
// catch (SocketException)
|
|
||||||
// {
|
|
||||||
// //Logger.Log(
|
|
||||||
// // "A SocketException occurred in UDPServer.AsyncBeginSend()",
|
|
||||||
// // Helpers.LogLevel.Error, se);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// rwLock.ReleaseReaderLock();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private void AsyncEndSend(IAsyncResult iar)
|
|
||||||
// {
|
|
||||||
// rwLock.AcquireReaderLock(-1);
|
|
||||||
|
|
||||||
// if (!shutdownFlag)
|
|
||||||
// {
|
|
||||||
// UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
|
|
||||||
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// int bytesSent = udpSocket.EndSendTo(iar);
|
|
||||||
|
|
||||||
// // note that call to the abstract PacketSent() method - we are passing the number
|
|
||||||
// // of bytes sent in a separate parameter, since we can't use buffer.DataLength which
|
|
||||||
// // is the number of bytes to send (or bytes received depending upon whether this
|
|
||||||
// // buffer was part of a send or a receive).
|
|
||||||
// PacketSent(buffer, bytesSent);
|
|
||||||
// }
|
|
||||||
// catch (SocketException)
|
|
||||||
// {
|
|
||||||
// //Logger.Log(
|
|
||||||
// // "A SocketException occurred in UDPServer.AsyncEndSend()",
|
|
||||||
// // Helpers.LogLevel.Error, se);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Interlocked.Decrement(ref rwOperationCount);
|
|
||||||
// rwLock.ReleaseReaderLock();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//--------- Original Version -------------------
|
|
||||||
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ClientStack.LindenUDP
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Base UDP server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class OpenSimUDPBase
|
public abstract class OpenSimUDPBase
|
||||||
{
|
{
|
||||||
// these abstract methods must be implemented in a derived class to actually do
|
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
// something with the packets that are sent and received.
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method is called when an incoming packet is received
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">Incoming packet buffer</param>
|
||||||
protected abstract void PacketReceived(UDPPacketBuffer buffer);
|
protected abstract void PacketReceived(UDPPacketBuffer buffer);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method is called when an outgoing packet is sent
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">Outgoing packet buffer</param>
|
||||||
|
/// <param name="bytesSent">Number of bytes written to the wire</param>
|
||||||
protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent);
|
protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent);
|
||||||
|
|
||||||
// the port to listen on
|
/// <summary>UDP port to bind to in server mode</summary>
|
||||||
internal int udpPort;
|
protected int m_udpPort;
|
||||||
|
|
||||||
// the UDP socket
|
/// <summary>Local IP address to bind to in server mode</summary>
|
||||||
private Socket udpSocket;
|
protected IPAddress m_localBindAddress;
|
||||||
|
|
||||||
// the all important shutdownFlag.
|
/// <summary>UDP socket, used in either client or server mode</summary>
|
||||||
private volatile bool shutdownFlag = true;
|
private Socket m_udpSocket;
|
||||||
|
|
||||||
// the remote endpoint to communicate with
|
/// <summary>Flag to process packets asynchronously or synchronously</summary>
|
||||||
protected IPEndPoint remoteEndPoint = null;
|
private bool m_asyncPacketHandling;
|
||||||
|
|
||||||
|
/// <summary>The all important shutdown flag</summary>
|
||||||
|
private volatile bool m_shutdownFlag = true;
|
||||||
|
|
||||||
|
/// <summary>Returns true if the server is currently listening, otherwise false</summary>
|
||||||
|
public bool IsRunning { get { return !m_shutdownFlag; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize the UDP packet handler in server mode
|
/// Default constructor
|
||||||
/// </summary>
|
/// </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="port">Port to listening for incoming UDP packets on</param>
|
||||||
public OpenSimUDPBase(int port)
|
public OpenSimUDPBase(IPAddress bindAddress, int port)
|
||||||
{
|
{
|
||||||
udpPort = port;
|
m_localBindAddress = bindAddress;
|
||||||
|
m_udpPort = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize the UDP packet handler in client mode
|
/// Start the UDP server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="endPoint">Remote UDP server to connect to</param>
|
/// <param name="recvBufferSize">The size of the receive buffer for
|
||||||
public OpenSimUDPBase(IPEndPoint endPoint)
|
/// 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</param>
|
||||||
|
/// <param name="asyncPacketHandling">Set this to true to start
|
||||||
|
/// receiving more packets while current packet handler callbacks are
|
||||||
|
/// still running. Setting this to false will complete each packet
|
||||||
|
/// callback before the next packet is processed</param>
|
||||||
|
/// <remarks>This method will attempt to set the SIO_UDP_CONNRESET flag
|
||||||
|
/// on the socket to get newer versions of Windows to behave in a sane
|
||||||
|
/// 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)
|
||||||
{
|
{
|
||||||
remoteEndPoint = endPoint;
|
m_asyncPacketHandling = asyncPacketHandling;
|
||||||
udpPort = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
if (m_shutdownFlag)
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public void Start()
|
|
||||||
{
|
|
||||||
if (shutdownFlag)
|
|
||||||
{
|
{
|
||||||
const int SIO_UDP_CONNRESET = -1744830452;
|
const int SIO_UDP_CONNRESET = -1744830452;
|
||||||
|
|
||||||
IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort);
|
IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
|
||||||
udpSocket = new Socket(
|
|
||||||
|
m_udpSocket = new Socket(
|
||||||
AddressFamily.InterNetwork,
|
AddressFamily.InterNetwork,
|
||||||
SocketType.Dgram,
|
SocketType.Dgram,
|
||||||
ProtocolType.Udp);
|
ProtocolType.Udp);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// this udp socket flag is not supported under mono,
|
// This udp socket flag is not supported under mono,
|
||||||
// so we'll catch the exception and continue
|
// so we'll catch the exception and continue
|
||||||
udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null);
|
m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null);
|
||||||
|
m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set");
|
||||||
}
|
}
|
||||||
catch (SocketException)
|
catch (SocketException)
|
||||||
{
|
{
|
||||||
Logger.DebugLog("UDP SIO_UDP_CONNRESET flag not supported on this platform");
|
m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring");
|
||||||
}
|
}
|
||||||
udpSocket.Bind(ipep);
|
|
||||||
|
if (recvBufferSize != 0)
|
||||||
|
m_udpSocket.ReceiveBufferSize = recvBufferSize;
|
||||||
|
|
||||||
|
m_udpSocket.Bind(ipep);
|
||||||
|
|
||||||
// we're not shutting down, we're starting up
|
// we're not shutting down, we're starting up
|
||||||
shutdownFlag = false;
|
m_shutdownFlag = false;
|
||||||
|
|
||||||
// kick off an async receive. The Start() method will return, the
|
// kick off an async receive. The Start() method will return, the
|
||||||
// actual receives will occur asynchronously and will be caught in
|
// actual receives will occur asynchronously and will be caught in
|
||||||
|
@ -423,41 +141,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Stops the UDP server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
if (!shutdownFlag)
|
if (!m_shutdownFlag)
|
||||||
{
|
{
|
||||||
// wait indefinitely for a writer lock. Once this is called, the .NET runtime
|
// wait indefinitely for a writer lock. Once this is called, the .NET runtime
|
||||||
// will deny any more reader locks, in effect blocking all other send/receive
|
// will deny any more reader locks, in effect blocking all other send/receive
|
||||||
// threads. Once we have the lock, we set shutdownFlag to inform the other
|
// threads. Once we have the lock, we set shutdownFlag to inform the other
|
||||||
// threads that the socket is closed.
|
// threads that the socket is closed.
|
||||||
shutdownFlag = true;
|
m_shutdownFlag = true;
|
||||||
udpSocket.Close();
|
m_udpSocket.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public bool IsRunning
|
|
||||||
{
|
|
||||||
get { return !shutdownFlag; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AsyncBeginReceive()
|
private void AsyncBeginReceive()
|
||||||
{
|
{
|
||||||
// allocate a packet buffer
|
// allocate a packet buffer
|
||||||
//WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut();
|
//WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut();
|
||||||
UDPPacketBuffer buf = new UDPPacketBuffer();
|
UDPPacketBuffer buf = new UDPPacketBuffer();
|
||||||
|
|
||||||
if (!shutdownFlag)
|
if (!m_shutdownFlag)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// kick off an async read
|
// kick off an async read
|
||||||
udpSocket.BeginReceiveFrom(
|
m_udpSocket.BeginReceiveFrom(
|
||||||
//wrappedBuffer.Instance.Data,
|
//wrappedBuffer.Instance.Data,
|
||||||
buf.Data,
|
buf.Data,
|
||||||
0,
|
0,
|
||||||
|
@ -472,13 +182,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
if (e.SocketErrorCode == SocketError.ConnectionReset)
|
if (e.SocketErrorCode == SocketError.ConnectionReset)
|
||||||
{
|
{
|
||||||
Logger.Log("SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + udpPort, Helpers.LogLevel.Error);
|
m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort);
|
||||||
bool salvaged = false;
|
bool salvaged = false;
|
||||||
while (!salvaged)
|
while (!salvaged)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
udpSocket.BeginReceiveFrom(
|
m_udpSocket.BeginReceiveFrom(
|
||||||
//wrappedBuffer.Instance.Data,
|
//wrappedBuffer.Instance.Data,
|
||||||
buf.Data,
|
buf.Data,
|
||||||
0,
|
0,
|
||||||
|
@ -494,7 +204,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
catch (ObjectDisposedException) { return; }
|
catch (ObjectDisposedException) { return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Log("Salvaged the UDP listener on port " + udpPort, Helpers.LogLevel.Info);
|
m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ObjectDisposedException) { }
|
catch (ObjectDisposedException) { }
|
||||||
|
@ -505,9 +215,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
// Asynchronous receive operations will complete here through the call
|
// Asynchronous receive operations will complete here through the call
|
||||||
// to AsyncBeginReceive
|
// to AsyncBeginReceive
|
||||||
if (!shutdownFlag)
|
if (!m_shutdownFlag)
|
||||||
{
|
{
|
||||||
// start another receive - this keeps the server going!
|
// Asynchronous mode will start another receive before the
|
||||||
|
// callback for this packet is even fired. Very parallel :-)
|
||||||
|
if (m_asyncPacketHandling)
|
||||||
AsyncBeginReceive();
|
AsyncBeginReceive();
|
||||||
|
|
||||||
// get the buffer that was created in AsyncBeginReceive
|
// get the buffer that was created in AsyncBeginReceive
|
||||||
|
@ -520,7 +232,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
// get the length of data actually read from the socket, store it with the
|
// get the length of data actually read from the socket, store it with the
|
||||||
// buffer
|
// buffer
|
||||||
buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
|
buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
|
||||||
|
|
||||||
// call the abstract method PacketReceived(), passing the buffer that
|
// call the abstract method PacketReceived(), passing the buffer that
|
||||||
// has just been filled from the socket read.
|
// has just been filled from the socket read.
|
||||||
|
@ -528,17 +240,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
catch (SocketException) { }
|
catch (SocketException) { }
|
||||||
catch (ObjectDisposedException) { }
|
catch (ObjectDisposedException) { }
|
||||||
//finally { wrappedBuffer.Dispose(); }
|
finally
|
||||||
|
{
|
||||||
|
//wrappedBuffer.Dispose();
|
||||||
|
|
||||||
|
// Synchronous mode waits until the packet callback completes
|
||||||
|
// before starting the receive to fetch another packet
|
||||||
|
if (!m_asyncPacketHandling)
|
||||||
|
AsyncBeginReceive();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AsyncBeginSend(UDPPacketBuffer buf)
|
public void AsyncBeginSend(UDPPacketBuffer buf)
|
||||||
{
|
{
|
||||||
if (!shutdownFlag)
|
if (!m_shutdownFlag)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
udpSocket.BeginSendTo(
|
m_udpSocket.BeginSendTo(
|
||||||
buf.Data,
|
buf.Data,
|
||||||
0,
|
0,
|
||||||
buf.DataLength,
|
buf.DataLength,
|
||||||
|
@ -557,7 +278,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
|
UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
|
||||||
int bytesSent = udpSocket.EndSendTo(result);
|
int bytesSent = m_udpSocket.EndSendTo(result);
|
||||||
|
|
||||||
PacketSent(buf, bytesSent);
|
PacketSent(buf, bytesSent);
|
||||||
}
|
}
|
||||||
|
@ -566,4 +287,3 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using OpenSim.Framework;
|
||||||
using Nini.Config;
|
using Nini.Config;
|
||||||
|
|
||||||
namespace OpenSim.Region.ClientStack.LindenUDP
|
namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
@ -45,12 +46,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
public int Wind;
|
public int Wind;
|
||||||
/// <summary>Drip rate for cloud packets</summary>
|
/// <summary>Drip rate for cloud packets</summary>
|
||||||
public int Cloud;
|
public int Cloud;
|
||||||
/// <summary>Drip rate for task (state and transaction) packets</summary>
|
/// <summary>Drip rate for task packets</summary>
|
||||||
public int Task;
|
public int Task;
|
||||||
/// <summary>Drip rate for texture packets</summary>
|
/// <summary>Drip rate for texture packets</summary>
|
||||||
public int Texture;
|
public int Texture;
|
||||||
/// <summary>Drip rate for asset packets</summary>
|
/// <summary>Drip rate for asset packets</summary>
|
||||||
public int Asset;
|
public int Asset;
|
||||||
|
/// <summary>Drip rate for state packets</summary>
|
||||||
|
public int State;
|
||||||
|
/// <summary>Drip rate for the parent token bucket</summary>
|
||||||
|
public int Total;
|
||||||
|
|
||||||
/// <summary>Maximum burst rate for resent packets</summary>
|
/// <summary>Maximum burst rate for resent packets</summary>
|
||||||
public int ResendLimit;
|
public int ResendLimit;
|
||||||
|
@ -66,6 +71,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
public int TextureLimit;
|
public int TextureLimit;
|
||||||
/// <summary>Maximum burst rate for asset packets</summary>
|
/// <summary>Maximum burst rate for asset packets</summary>
|
||||||
public int AssetLimit;
|
public int AssetLimit;
|
||||||
|
/// <summary>Maximum burst rate for state packets</summary>
|
||||||
|
public int StateLimit;
|
||||||
|
/// <summary>Burst rate for the parent token bucket</summary>
|
||||||
|
public int TotalLimit;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
|
@ -77,23 +86,81 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"];
|
IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"];
|
||||||
|
|
||||||
Resend = throttleConfig.GetInt("ResendDefault", 12500);
|
Resend = throttleConfig.GetInt("resend_default", 12500);
|
||||||
Land = throttleConfig.GetInt("LandDefault", 500);
|
Land = throttleConfig.GetInt("land_default", 500);
|
||||||
Wind = throttleConfig.GetInt("WindDefault", 500);
|
Wind = throttleConfig.GetInt("wind_default", 500);
|
||||||
Cloud = throttleConfig.GetInt("CloudDefault", 500);
|
Cloud = throttleConfig.GetInt("cloud_default", 500);
|
||||||
Task = throttleConfig.GetInt("TaskDefault", 500);
|
Task = throttleConfig.GetInt("task_default", 500);
|
||||||
Texture = throttleConfig.GetInt("TextureDefault", 500);
|
Texture = throttleConfig.GetInt("texture_default", 500);
|
||||||
Asset = throttleConfig.GetInt("AssetDefault", 500);
|
Asset = throttleConfig.GetInt("asset_default", 500);
|
||||||
|
State = throttleConfig.GetInt("state_default", 500);
|
||||||
|
|
||||||
ResendLimit = throttleConfig.GetInt("ResendLimit", 18750);
|
Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
|
||||||
LandLimit = throttleConfig.GetInt("LandLimit", 29750);
|
|
||||||
WindLimit = throttleConfig.GetInt("WindLimit", 18750);
|
ResendLimit = throttleConfig.GetInt("resend_limit", 18750);
|
||||||
CloudLimit = throttleConfig.GetInt("CloudLimit", 18750);
|
LandLimit = throttleConfig.GetInt("land_limit", 29750);
|
||||||
TaskLimit = throttleConfig.GetInt("TaskLimit", 55750);
|
WindLimit = throttleConfig.GetInt("wind_limit", 18750);
|
||||||
TextureLimit = throttleConfig.GetInt("TextureLimit", 55750);
|
CloudLimit = throttleConfig.GetInt("cloud_limit", 18750);
|
||||||
AssetLimit = throttleConfig.GetInt("AssetLimit", 27500);
|
TaskLimit = throttleConfig.GetInt("task_limit", 18750);
|
||||||
|
TextureLimit = throttleConfig.GetInt("texture_limit", 55750);
|
||||||
|
AssetLimit = throttleConfig.GetInt("asset_limit", 27500);
|
||||||
|
State = throttleConfig.GetInt("state_limit", 37000);
|
||||||
|
|
||||||
|
TotalLimit = throttleConfig.GetInt("client_throttle_max_bps", 0);
|
||||||
}
|
}
|
||||||
catch (Exception) { }
|
catch (Exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetRate(ThrottleOutPacketType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ThrottleOutPacketType.Resend:
|
||||||
|
return Resend;
|
||||||
|
case ThrottleOutPacketType.Land:
|
||||||
|
return Land;
|
||||||
|
case ThrottleOutPacketType.Wind:
|
||||||
|
return Wind;
|
||||||
|
case ThrottleOutPacketType.Cloud:
|
||||||
|
return Cloud;
|
||||||
|
case ThrottleOutPacketType.Task:
|
||||||
|
return Task;
|
||||||
|
case ThrottleOutPacketType.Texture:
|
||||||
|
return Texture;
|
||||||
|
case ThrottleOutPacketType.Asset:
|
||||||
|
return Asset;
|
||||||
|
case ThrottleOutPacketType.State:
|
||||||
|
return State;
|
||||||
|
case ThrottleOutPacketType.Unknown:
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetLimit(ThrottleOutPacketType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ThrottleOutPacketType.Resend:
|
||||||
|
return ResendLimit;
|
||||||
|
case ThrottleOutPacketType.Land:
|
||||||
|
return LandLimit;
|
||||||
|
case ThrottleOutPacketType.Wind:
|
||||||
|
return WindLimit;
|
||||||
|
case ThrottleOutPacketType.Cloud:
|
||||||
|
return CloudLimit;
|
||||||
|
case ThrottleOutPacketType.Task:
|
||||||
|
return TaskLimit;
|
||||||
|
case ThrottleOutPacketType.Texture:
|
||||||
|
return TextureLimit;
|
||||||
|
case ThrottleOutPacketType.Asset:
|
||||||
|
return AssetLimit;
|
||||||
|
case ThrottleOutPacketType.State:
|
||||||
|
return StateLimit;
|
||||||
|
case ThrottleOutPacketType.Unknown:
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes all elements from the collection
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
packets.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the packet with the lowest sequence number
|
/// Gets the packet with the lowest sequence number
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -43,6 +43,7 @@ using Mono.Addins;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Console;
|
||||||
using OpenSim.Region.Framework.Interfaces;
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
using OpenSim.Services.Interfaces;
|
using OpenSim.Services.Interfaces;
|
||||||
|
@ -54,7 +55,7 @@ using OpenSim.Services.Interfaces;
|
||||||
namespace Flotsam.RegionModules.AssetCache
|
namespace Flotsam.RegionModules.AssetCache
|
||||||
{
|
{
|
||||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
|
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
|
||||||
public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache
|
public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache, IAssetService
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log =
|
private static readonly ILog m_log =
|
||||||
LogManager.GetLogger(
|
LogManager.GetLogger(
|
||||||
|
@ -102,6 +103,11 @@ namespace Flotsam.RegionModules.AssetCache
|
||||||
|
|
||||||
private System.Timers.Timer m_CachCleanTimer = new System.Timers.Timer();
|
private System.Timers.Timer m_CachCleanTimer = new System.Timers.Timer();
|
||||||
|
|
||||||
|
private IAssetService m_AssetService = null;
|
||||||
|
private List<Scene> m_Scenes = new List<Scene>();
|
||||||
|
|
||||||
|
private bool m_DeepScanBeforePurge = false;
|
||||||
|
|
||||||
public FlotsamAssetCache()
|
public FlotsamAssetCache()
|
||||||
{
|
{
|
||||||
m_InvalidChars.AddRange(Path.GetInvalidPathChars());
|
m_InvalidChars.AddRange(Path.GetInvalidPathChars());
|
||||||
|
@ -122,6 +128,7 @@ namespace Flotsam.RegionModules.AssetCache
|
||||||
{
|
{
|
||||||
IConfig moduleConfig = source.Configs["Modules"];
|
IConfig moduleConfig = source.Configs["Modules"];
|
||||||
|
|
||||||
|
|
||||||
if (moduleConfig != null)
|
if (moduleConfig != null)
|
||||||
{
|
{
|
||||||
string name = moduleConfig.GetString("AssetCaching", "");
|
string name = moduleConfig.GetString("AssetCaching", "");
|
||||||
|
@ -195,6 +202,12 @@ namespace Flotsam.RegionModules.AssetCache
|
||||||
|
|
||||||
m_CacheWarnAt = assetConfig.GetInt("CacheWarnAt", 30000);
|
m_CacheWarnAt = assetConfig.GetInt("CacheWarnAt", 30000);
|
||||||
|
|
||||||
|
m_DeepScanBeforePurge = assetConfig.GetBoolean("DeepScanBeforePurge", false);
|
||||||
|
|
||||||
|
MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache status", "fcache status", "Display cache status", HandleConsoleCommand);
|
||||||
|
MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache clear", "fcache clear [file] [memory]", "Remove all assets in the file and/or memory cache", HandleConsoleCommand);
|
||||||
|
MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache assets", "fcache assets", "Attempt a deep scan and cache of all assets in all scenes", HandleConsoleCommand);
|
||||||
|
MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache expire", "fcache expire <datetime>", "Purge cached assets older then the specified date/time", HandleConsoleCommand);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,16 +226,23 @@ namespace Flotsam.RegionModules.AssetCache
|
||||||
if (m_Enabled)
|
if (m_Enabled)
|
||||||
{
|
{
|
||||||
scene.RegisterModuleInterface<IImprovedAssetCache>(this);
|
scene.RegisterModuleInterface<IImprovedAssetCache>(this);
|
||||||
|
m_Scenes.Add(scene);
|
||||||
|
|
||||||
//scene.AddCommand(this, "flotsamcache", "", "Display a list of console commands for the Flotsam Asset Cache", HandleConsoleCommand);
|
if (m_AssetService == null)
|
||||||
scene.AddCommand(this, "flotsamcache counts", "flotsamcache counts", "Display the number of cached assets", HandleConsoleCommand);
|
{
|
||||||
scene.AddCommand(this, "flotsamcache clearmem", "flotsamcache clearmem", "Remove all assets cached in memory", HandleConsoleCommand);
|
m_AssetService = scene.RequestModuleInterface<IAssetService>();
|
||||||
scene.AddCommand(this, "flotsamcache clearfile", "flotsamcache clearfile", "Remove all assets cached on disk", HandleConsoleCommand);
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveRegion(Scene scene)
|
public void RemoveRegion(Scene scene)
|
||||||
{
|
{
|
||||||
|
if (m_Enabled)
|
||||||
|
{
|
||||||
|
scene.UnregisterModuleInterface<IImprovedAssetCache>(this);
|
||||||
|
m_Scenes.Remove(scene);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegionLoaded(Scene scene)
|
public void RegionLoaded(Scene scene)
|
||||||
|
@ -442,31 +462,47 @@ namespace Flotsam.RegionModules.AssetCache
|
||||||
if (m_LogLevel >= 2)
|
if (m_LogLevel >= 2)
|
||||||
m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Checking for expired files older then {0}.", m_FileExpiration.ToString());
|
m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Checking for expired files older then {0}.", m_FileExpiration.ToString());
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
|
foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
|
||||||
{
|
{
|
||||||
CleanExpiredFiles(dir);
|
CleanExpiredFiles(dir, purgeLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Recurses through specified directory checking for expired asset files and deletes them. Also removes empty directories.
|
/// Recurses through specified directory checking for asset files last
|
||||||
|
/// accessed prior to the specified purge line and deletes them. Also
|
||||||
|
/// removes empty tier directories.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dir"></param>
|
/// <param name="dir"></param>
|
||||||
private void CleanExpiredFiles(string dir)
|
private void CleanExpiredFiles(string dir, DateTime purgeLine)
|
||||||
{
|
{
|
||||||
|
|
||||||
foreach (string file in Directory.GetFiles(dir))
|
foreach (string file in Directory.GetFiles(dir))
|
||||||
{
|
{
|
||||||
if (DateTime.Now - File.GetLastAccessTime(file) > m_FileExpiration)
|
if (File.GetLastAccessTime(file) < purgeLine)
|
||||||
{
|
{
|
||||||
File.Delete(file);
|
File.Delete(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recurse into lower tiers
|
||||||
foreach (string subdir in Directory.GetDirectories(dir))
|
foreach (string subdir in Directory.GetDirectories(dir))
|
||||||
{
|
{
|
||||||
CleanExpiredFiles(subdir);
|
CleanExpiredFiles(subdir, purgeLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if a tier directory is empty, if so, delete it
|
||||||
int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length;
|
int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length;
|
||||||
if (dirSize == 0)
|
if (dirSize == 0)
|
||||||
{
|
{
|
||||||
|
@ -478,6 +514,11 @@ namespace Flotsam.RegionModules.AssetCache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the filename for an AssetID stored in the file cache
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private string GetFileName(string id)
|
private string GetFileName(string id)
|
||||||
{
|
{
|
||||||
// Would it be faster to just hash the darn thing?
|
// Would it be faster to just hash the darn thing?
|
||||||
|
@ -496,14 +537,23 @@ namespace Flotsam.RegionModules.AssetCache
|
||||||
return Path.Combine(path, id);
|
return Path.Combine(path, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a file to the file cache, creating any nessesary
|
||||||
|
/// tier directories along the way
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename"></param>
|
||||||
|
/// <param name="asset"></param>
|
||||||
private void WriteFileCache(string filename, AssetBase asset)
|
private void WriteFileCache(string filename, AssetBase asset)
|
||||||
{
|
{
|
||||||
Stream stream = null;
|
Stream stream = null;
|
||||||
|
|
||||||
// Make sure the target cache directory exists
|
// Make sure the target cache directory exists
|
||||||
string directory = Path.GetDirectoryName(filename);
|
string directory = Path.GetDirectoryName(filename);
|
||||||
|
|
||||||
// Write file first to a temp name, so that it doesn't look
|
// Write file first to a temp name, so that it doesn't look
|
||||||
// like it's already cached while it's still writing.
|
// like it's already cached while it's still writing.
|
||||||
string tempname = Path.Combine(directory, Path.GetRandomFileName());
|
string tempname = Path.Combine(directory, Path.GetRandomFileName());
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(directory))
|
if (!Directory.Exists(directory))
|
||||||
|
@ -563,6 +613,11 @@ namespace Flotsam.RegionModules.AssetCache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Scan through the file cache, and return number of assets currently cached.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dir"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private int GetFileCacheCount(string dir)
|
private int GetFileCacheCount(string dir)
|
||||||
{
|
{
|
||||||
int count = Directory.GetFiles(dir).Length;
|
int count = Directory.GetFiles(dir).Length;
|
||||||
|
@ -575,29 +630,67 @@ namespace Flotsam.RegionModules.AssetCache
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Console Commands
|
/// <summary>
|
||||||
private void HandleConsoleCommand(string module, string[] cmdparams)
|
/// This notes the last time the Region had a deep asset scan performed on it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="RegionID"></param>
|
||||||
|
private void StampRegionStatusFile(UUID RegionID)
|
||||||
{
|
{
|
||||||
if (cmdparams.Length == 2)
|
string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + RegionID.ToString() + ".fac");
|
||||||
|
if (File.Exists(RegionCacheStatusFile))
|
||||||
{
|
{
|
||||||
string cmd = cmdparams[1];
|
File.SetLastWriteTime(RegionCacheStatusFile, DateTime.Now);
|
||||||
switch (cmd)
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
case "count":
|
File.WriteAllText(RegionCacheStatusFile, "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache.");
|
||||||
case "counts":
|
}
|
||||||
m_log.InfoFormat("[FLOTSAM ASSET CACHE] Memory Cache : {0}", m_MemoryCache.Count);
|
}
|
||||||
|
|
||||||
int fileCount = GetFileCacheCount(m_CacheDirectory);
|
/// <summary>
|
||||||
m_log.InfoFormat("[FLOTSAM ASSET CACHE] File Cache : {0}", fileCount);
|
/// 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
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private int CacheScenes()
|
||||||
|
{
|
||||||
|
UuidGatherer gatherer = new UuidGatherer(m_AssetService);
|
||||||
|
|
||||||
break;
|
Dictionary<UUID, int> assets = new Dictionary<UUID, int>();
|
||||||
|
foreach (Scene s in m_Scenes)
|
||||||
|
{
|
||||||
|
StampRegionStatusFile(s.RegionInfo.RegionID);
|
||||||
|
|
||||||
case "clearmem":
|
s.ForEachSOG(delegate(SceneObjectGroup e)
|
||||||
m_MemoryCache.Clear();
|
{
|
||||||
m_log.InfoFormat("[FLOTSAM ASSET CACHE] Memory Cache Cleared, there are now {0} items in the memory cache", m_MemoryCache.Count);
|
gatherer.GatherAssetUuids(e, assets);
|
||||||
break;
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
case "clearfile":
|
foreach (UUID assetID in assets.Keys)
|
||||||
|
{
|
||||||
|
string filename = GetFileName(assetID.ToString());
|
||||||
|
|
||||||
|
if (File.Exists(filename))
|
||||||
|
{
|
||||||
|
File.SetLastAccessTime(filename, DateTime.Now);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_AssetService.Get(assetID.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return assets.Keys.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes all cache contents
|
||||||
|
/// </summary>
|
||||||
|
private void ClearFileCache()
|
||||||
|
{
|
||||||
foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
|
foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -621,9 +714,96 @@ namespace Flotsam.RegionModules.AssetCache
|
||||||
LogException(e);
|
LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Console Commands
|
||||||
|
private void HandleConsoleCommand(string module, string[] cmdparams)
|
||||||
|
{
|
||||||
|
if (cmdparams.Length >= 2)
|
||||||
|
{
|
||||||
|
string cmd = cmdparams[1];
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
case "status":
|
||||||
|
m_log.InfoFormat("[FLOTSAM ASSET CACHE] Memory Cache : {0} assets", m_MemoryCache.Count);
|
||||||
|
|
||||||
|
int fileCount = GetFileCacheCount(m_CacheDirectory);
|
||||||
|
m_log.InfoFormat("[FLOTSAM ASSET CACHE] File Cache : {0} assets", fileCount);
|
||||||
|
|
||||||
|
foreach ( string s in Directory.GetFiles(m_CacheDirectory, "*.fac" ) )
|
||||||
|
{
|
||||||
|
m_log.Info("[FLOTSAM ASSET CACHE] Deep Scans were performed on the following regions:");
|
||||||
|
|
||||||
|
string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac","");
|
||||||
|
DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s);
|
||||||
|
m_log.InfoFormat("[FLOTSAM ASSET CACHE] Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss"));
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "clear":
|
||||||
|
if (cmdparams.Length < 3)
|
||||||
|
{
|
||||||
|
m_log.Warn("[FLOTSAM ASSET CACHE] Please specify memory and/or file cache.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
foreach (string s in cmdparams)
|
||||||
|
{
|
||||||
|
if (s.ToLower() == "memory")
|
||||||
|
{
|
||||||
|
m_MemoryCache.Clear();
|
||||||
|
m_log.Info("[FLOTSAM ASSET CACHE] Memory cache cleared.");
|
||||||
|
}
|
||||||
|
else if (s.ToLower() == "file")
|
||||||
|
{
|
||||||
|
ClearFileCache();
|
||||||
|
m_log.Info("[FLOTSAM ASSET CACHE] File cache cleared.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case "assets":
|
||||||
|
m_log.Info("[FLOTSAM ASSET CACHE] Caching all assets, in all scenes.");
|
||||||
|
|
||||||
|
Util.FireAndForget(delegate {
|
||||||
|
int assetsCached = CacheScenes();
|
||||||
|
m_log.InfoFormat("[FLOTSAM ASSET CACHE] Completed Scene Caching, {0} assets found.", assetsCached);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "expire":
|
||||||
|
|
||||||
|
|
||||||
|
if (cmdparams.Length >= 3)
|
||||||
|
{
|
||||||
|
m_log.InfoFormat("[FLOTSAM ASSET CACHE] Invalid parameters for Expire, please specify a valid date & time", cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
string s_expirationDate = "";
|
||||||
|
DateTime expirationDate;
|
||||||
|
|
||||||
|
if (cmdparams.Length > 3)
|
||||||
|
{
|
||||||
|
s_expirationDate = string.Join(" ", cmdparams, 2, cmdparams.Length - 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_expirationDate = cmdparams[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!DateTime.TryParse(s_expirationDate, out expirationDate))
|
||||||
|
{
|
||||||
|
m_log.InfoFormat("[FLOTSAM ASSET CACHE] {0} is not a valid date & time", cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CleanExpiredFiles(m_CacheDirectory, expirationDate);
|
||||||
|
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
m_log.InfoFormat("[FLOTSAM ASSET CACHE] Unknown command {0}", cmd);
|
m_log.InfoFormat("[FLOTSAM ASSET CACHE] Unknown command {0}", cmd);
|
||||||
break;
|
break;
|
||||||
|
@ -631,13 +811,66 @@ namespace Flotsam.RegionModules.AssetCache
|
||||||
}
|
}
|
||||||
else if (cmdparams.Length == 1)
|
else if (cmdparams.Length == 1)
|
||||||
{
|
{
|
||||||
m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache counts - Display the number of cached assets");
|
m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache status - Display cache status");
|
||||||
m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearmem - Remove all assets cached in memory");
|
m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearmem - Remove all assets cached in memory");
|
||||||
m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearfile - Remove all assets cached on disk");
|
m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearfile - Remove all assets cached on disk");
|
||||||
|
m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache cachescenes - Attempt a deep cache of all assets in all scenes");
|
||||||
|
m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache <datetime> - Purge assets older then the specified date & time");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region IAssetService Members
|
||||||
|
|
||||||
|
|
||||||
|
public AssetMetadata GetMetadata(string id)
|
||||||
|
{
|
||||||
|
AssetBase asset = Get(id);
|
||||||
|
return asset.Metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetData(string id)
|
||||||
|
{
|
||||||
|
AssetBase asset = Get(id);
|
||||||
|
return asset.Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Get(string id, object sender, AssetRetrieved handler)
|
||||||
|
{
|
||||||
|
AssetBase asset = Get(id);
|
||||||
|
handler(id, sender, asset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Store(AssetBase asset)
|
||||||
|
{
|
||||||
|
if ((asset.FullID == null) || (asset.FullID == UUID.Zero))
|
||||||
|
{
|
||||||
|
asset.FullID = UUID.Random();
|
||||||
|
}
|
||||||
|
|
||||||
|
Cache(asset);
|
||||||
|
|
||||||
|
return asset.ID;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool UpdateContent(string id, byte[] data)
|
||||||
|
{
|
||||||
|
AssetBase asset = Get(id);
|
||||||
|
asset.Data = data;
|
||||||
|
Cache(asset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Delete(string id)
|
||||||
|
{
|
||||||
|
Expire(id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -36,6 +36,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
|
||||||
{
|
{
|
||||||
public class GodsModule : IRegionModule, IGodsModule
|
public class GodsModule : IRegionModule, IGodsModule
|
||||||
{
|
{
|
||||||
|
/// <summary>Special UUID for actions that apply to all agents</summary>
|
||||||
|
private static readonly UUID ALL_AGENTS = new UUID("44e87126-e794-4ded-05b3-7c42da3d5cdb");
|
||||||
|
|
||||||
protected Scene m_scene;
|
protected Scene m_scene;
|
||||||
protected IDialogModule m_dialogModule;
|
protected IDialogModule m_dialogModule;
|
||||||
|
|
||||||
|
@ -99,8 +102,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
|
||||||
/// <param name="reason">The message to send to the user after it's been turned into a field</param>
|
/// <param name="reason">The message to send to the user after it's been turned into a field</param>
|
||||||
public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason)
|
public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason)
|
||||||
{
|
{
|
||||||
// For some reason the client sends this seemingly hard coded UUID for kicking everyone. Dun-know.
|
UUID kickUserID = ALL_AGENTS;
|
||||||
UUID kickUserID = new UUID("44e87126e7944ded05b37c42da3d5cdb");
|
|
||||||
|
|
||||||
ScenePresence sp = m_scene.GetScenePresence(agentID);
|
ScenePresence sp = m_scene.GetScenePresence(agentID);
|
||||||
|
|
||||||
|
@ -110,11 +112,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
|
||||||
{
|
{
|
||||||
if (agentID == kickUserID)
|
if (agentID == kickUserID)
|
||||||
{
|
{
|
||||||
m_scene.ClientManager.ForEachClient(
|
string reasonStr = Utils.BytesToString(reason);
|
||||||
|
|
||||||
|
m_scene.ClientManager.ForEach(
|
||||||
delegate(IClientAPI controller)
|
delegate(IClientAPI controller)
|
||||||
{
|
{
|
||||||
if (controller.AgentId != godID)
|
if (controller.AgentId != godID)
|
||||||
controller.Kick(Utils.BytesToString(reason));
|
controller.Kick(reasonStr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -128,7 +132,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
|
||||||
{
|
{
|
||||||
// Possibly this should really be p.Close() though that method doesn't send a close
|
// Possibly this should really be p.Close() though that method doesn't send a close
|
||||||
// to the client
|
// to the client
|
||||||
p.ControllingClient.Close(true);
|
p.ControllingClient.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -138,7 +142,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
|
||||||
m_scene.SceneGraph.removeUserCount(!sp.IsChildAgent);
|
m_scene.SceneGraph.removeUserCount(!sp.IsChildAgent);
|
||||||
|
|
||||||
sp.ControllingClient.Kick(Utils.BytesToString(reason));
|
sp.ControllingClient.Kick(Utils.BytesToString(reason));
|
||||||
sp.ControllingClient.Close(true);
|
sp.ControllingClient.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -1267,7 +1267,7 @@ namespace OpenSim.Region.CoreModules.InterGrid
|
||||||
if (avToBeKilled.IsChildAgent)
|
if (avToBeKilled.IsChildAgent)
|
||||||
{
|
{
|
||||||
m_mod.DeleteOGPState(avUUID);
|
m_mod.DeleteOGPState(avUUID);
|
||||||
avToBeKilled.ControllingClient.Close(true);
|
avToBeKilled.ControllingClient.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
|
||||||
public string body;
|
public string body;
|
||||||
public int responseCode;
|
public int responseCode;
|
||||||
public string responseBody;
|
public string responseBody;
|
||||||
public ManualResetEvent ev;
|
//public ManualResetEvent ev;
|
||||||
public bool requestDone;
|
public bool requestDone;
|
||||||
public int startTime;
|
public int startTime;
|
||||||
public string uri;
|
public string uri;
|
||||||
|
@ -456,7 +456,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
|
||||||
requestData.headers["x-query-string"] = queryString;
|
requestData.headers["x-query-string"] = queryString;
|
||||||
requestData.headers["x-script-url"] = url.url;
|
requestData.headers["x-script-url"] = url.url;
|
||||||
|
|
||||||
requestData.ev = new ManualResetEvent(false);
|
//requestData.ev = new ManualResetEvent(false);
|
||||||
lock (url.requests)
|
lock (url.requests)
|
||||||
{
|
{
|
||||||
url.requests.Add(requestID, requestData);
|
url.requests.Add(requestID, requestData);
|
||||||
|
|
|
@ -31,6 +31,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Communications.Cache;
|
||||||
using OpenSim.Server.Base;
|
using OpenSim.Server.Base;
|
||||||
using OpenSim.Region.Framework.Interfaces;
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
@ -40,7 +41,7 @@ using OpenMetaverse;
|
||||||
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
|
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
|
||||||
{
|
{
|
||||||
public class HGAssetBroker :
|
public class HGAssetBroker :
|
||||||
ISharedRegionModule, IAssetService
|
ISharedRegionModule, IAssetService, IHyperAssetService
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log =
|
private static readonly ILog m_log =
|
||||||
LogManager.GetLogger(
|
LogManager.GetLogger(
|
||||||
|
@ -50,6 +51,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
|
||||||
private IAssetService m_GridService;
|
private IAssetService m_GridService;
|
||||||
private IAssetService m_HGService;
|
private IAssetService m_HGService;
|
||||||
|
|
||||||
|
private Scene m_aScene;
|
||||||
|
private string m_LocalAssetServiceURI;
|
||||||
|
|
||||||
private bool m_Enabled = false;
|
private bool m_Enabled = false;
|
||||||
|
|
||||||
public Type ReplaceableInterface
|
public Type ReplaceableInterface
|
||||||
|
@ -114,6 +118,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_LocalAssetServiceURI = assetConfig.GetString("AssetServerURI", string.Empty);
|
||||||
|
if (m_LocalAssetServiceURI == string.Empty)
|
||||||
|
{
|
||||||
|
IConfig netConfig = source.Configs["Network"];
|
||||||
|
m_LocalAssetServiceURI = netConfig.GetString("asset_server_url", string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_LocalAssetServiceURI != string.Empty)
|
||||||
|
m_LocalAssetServiceURI = m_LocalAssetServiceURI.Trim('/');
|
||||||
|
|
||||||
m_Enabled = true;
|
m_Enabled = true;
|
||||||
m_log.Info("[HG ASSET CONNECTOR]: HG asset broker enabled");
|
m_log.Info("[HG ASSET CONNECTOR]: HG asset broker enabled");
|
||||||
}
|
}
|
||||||
|
@ -133,7 +147,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
|
||||||
if (!m_Enabled)
|
if (!m_Enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
m_aScene = scene;
|
||||||
|
|
||||||
scene.RegisterModuleInterface<IAssetService>(this);
|
scene.RegisterModuleInterface<IAssetService>(this);
|
||||||
|
scene.RegisterModuleInterface<IHyperAssetService>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveRegion(Scene scene)
|
public void RemoveRegion(Scene scene)
|
||||||
|
@ -344,5 +361,30 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
|
||||||
else
|
else
|
||||||
return m_GridService.Delete(id);
|
return m_GridService.Delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region IHyperAssetService
|
||||||
|
|
||||||
|
public string GetUserAssetServer(UUID userID)
|
||||||
|
{
|
||||||
|
CachedUserInfo uinfo = m_aScene.CommsManager.UserProfileCacheService.GetUserDetails(userID);
|
||||||
|
if ((uinfo != null) && (uinfo.UserProfile != null))
|
||||||
|
{
|
||||||
|
if ((uinfo.UserProfile.UserAssetURI == string.Empty) || (uinfo.UserProfile.UserAssetURI == ""))
|
||||||
|
return m_LocalAssetServiceURI;
|
||||||
|
return uinfo.UserProfile.UserAssetURI.Trim('/');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we don't know anyting about this user
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetSimAssetServer()
|
||||||
|
{
|
||||||
|
return m_LocalAssetServiceURI;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -759,6 +759,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected bool IsLocalRegion(ulong handle)
|
protected bool IsLocalRegion(ulong handle)
|
||||||
{
|
{
|
||||||
return m_LocalScenes.ContainsKey(handle);
|
return m_LocalScenes.ContainsKey(handle);
|
||||||
|
|
|
@ -159,6 +159,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
|
||||||
/// <returns>true if the item was successfully added</returns>
|
/// <returns>true if the item was successfully added</returns>
|
||||||
public bool AddItem(InventoryItemBase item)
|
public bool AddItem(InventoryItemBase item)
|
||||||
{
|
{
|
||||||
|
if (item == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (item.Folder == UUID.Zero)
|
if (item.Folder == UUID.Zero)
|
||||||
{
|
{
|
||||||
InventoryFolderBase f = GetFolderForType(item.Owner, (AssetType)item.AssetType);
|
InventoryFolderBase f = GetFolderForType(item.Owner, (AssetType)item.AssetType);
|
||||||
|
|
|
@ -386,7 +386,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (IsLocalGridUser(item.Owner))
|
if (IsLocalGridUser(item.Owner))
|
||||||
|
{
|
||||||
return m_GridService.AddItem(item);
|
return m_GridService.AddItem(item);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UUID sessionID = GetSessionID(item.Owner);
|
UUID sessionID = GetSessionID(item.Owner);
|
||||||
|
|
|
@ -343,7 +343,9 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||||
|
|
||||||
lock (scene.WestBorders)
|
lock (scene.WestBorders)
|
||||||
{
|
{
|
||||||
scene.WestBorders[0].BorderLine.Z += (int) Constants.RegionSize; //auto teleport West
|
|
||||||
|
|
||||||
|
scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - conn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West
|
||||||
|
|
||||||
// Trigger auto teleport to root region
|
// Trigger auto teleport to root region
|
||||||
scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
|
scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
|
||||||
|
@ -410,7 +412,7 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||||
conn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize;
|
conn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize;
|
||||||
lock (scene.SouthBorders)
|
lock (scene.SouthBorders)
|
||||||
{
|
{
|
||||||
scene.SouthBorders[0].BorderLine.Z += (int) Constants.RegionSize; //auto teleport south
|
scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - conn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south
|
||||||
scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
|
scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
|
||||||
scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY;
|
scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY;
|
||||||
}
|
}
|
||||||
|
@ -481,7 +483,7 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||||
|
|
||||||
lock (scene.SouthBorders)
|
lock (scene.SouthBorders)
|
||||||
{
|
{
|
||||||
scene.SouthBorders[0].BorderLine.Z += (int) Constants.RegionSize; //auto teleport south
|
scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - conn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south
|
||||||
scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
|
scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
|
||||||
scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY;
|
scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY;
|
||||||
}
|
}
|
||||||
|
@ -503,7 +505,7 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||||
|
|
||||||
lock (scene.WestBorders)
|
lock (scene.WestBorders)
|
||||||
{
|
{
|
||||||
scene.WestBorders[0].BorderLine.Z += (int) Constants.RegionSize; //auto teleport West
|
scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - conn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West
|
||||||
scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
|
scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
|
||||||
scene.WestBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY;
|
scene.WestBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY;
|
||||||
}
|
}
|
||||||
|
|
|
@ -813,7 +813,7 @@ namespace OpenSim.Region.Examples.SimpleModule
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close(bool ShutdownCircuit)
|
public void Close()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -833,6 +833,11 @@ namespace OpenSim.Region.Examples.SimpleModule
|
||||||
set { m_circuitCode = value; }
|
set { m_circuitCode = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IPEndPoint RemoteEndPoint
|
||||||
|
{
|
||||||
|
get { return new IPEndPoint(IPAddress.Loopback, (ushort)m_circuitCode); }
|
||||||
|
}
|
||||||
|
|
||||||
public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message)
|
public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
using System;
|
||||||
|
using OpenMetaverse;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Framework.Interfaces
|
||||||
|
{
|
||||||
|
public interface IHyperAssetService
|
||||||
|
{
|
||||||
|
string GetUserAssetServer(UUID userID);
|
||||||
|
string GetSimAssetServer();
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,6 +35,7 @@ using OpenSim.Framework;
|
||||||
using OpenSim.Framework.Communications.Cache;
|
using OpenSim.Framework.Communications.Cache;
|
||||||
using OpenSim.Framework.Communications.Clients;
|
using OpenSim.Framework.Communications.Clients;
|
||||||
using OpenSim.Region.Framework.Scenes.Serialization;
|
using OpenSim.Region.Framework.Scenes.Serialization;
|
||||||
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
using OpenSim.Services.Interfaces;
|
using OpenSim.Services.Interfaces;
|
||||||
|
|
||||||
//using HyperGrid.Framework;
|
//using HyperGrid.Framework;
|
||||||
|
@ -52,13 +53,13 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
|
||||||
|
|
||||||
private Scene m_scene;
|
private Scene m_scene;
|
||||||
|
|
||||||
private IHyperlinkService m_hyper;
|
private IHyperAssetService m_hyper;
|
||||||
IHyperlinkService HyperlinkService
|
IHyperAssetService HyperlinkAssets
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (m_hyper == null)
|
if (m_hyper == null)
|
||||||
m_hyper = m_scene.RequestModuleInterface<IHyperlinkService>();
|
m_hyper = m_scene.RequestModuleInterface<IHyperAssetService>();
|
||||||
return m_hyper;
|
return m_hyper;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,7 +100,7 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
|
||||||
|
|
||||||
if (asset != null)
|
if (asset != null)
|
||||||
{
|
{
|
||||||
m_log.Debug("[HGScene]: Asset made it to asset cache. " + asset.Name + " " + assetID);
|
m_log.DebugFormat("[HGScene]: Copied asset {0} from {1} to local asset server. ", asset.ID, url);
|
||||||
return asset;
|
return asset;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -129,6 +130,7 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
|
||||||
}
|
}
|
||||||
|
|
||||||
m_scene.AssetService.Store(asset1);
|
m_scene.AssetService.Store(asset1);
|
||||||
|
m_log.DebugFormat("[HGScene]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -166,35 +168,33 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
|
||||||
#region Public interface
|
#region Public interface
|
||||||
|
|
||||||
public void Get(UUID assetID, UUID ownerID)
|
public void Get(UUID assetID, UUID ownerID)
|
||||||
{
|
|
||||||
if (!HyperlinkService.IsLocalUser(ownerID))
|
|
||||||
{
|
{
|
||||||
// Get the item from the remote asset server onto the local AssetCache
|
// Get the item from the remote asset server onto the local AssetCache
|
||||||
// and place an entry in m_assetMap
|
// and place an entry in m_assetMap
|
||||||
|
|
||||||
string userAssetURL = UserAssetURL(ownerID);
|
string userAssetURL = HyperlinkAssets.GetUserAssetServer(ownerID);
|
||||||
if (userAssetURL != null)
|
if ((userAssetURL != string.Empty) && (userAssetURL != HyperlinkAssets.GetSimAssetServer()))
|
||||||
{
|
{
|
||||||
m_log.Debug("[HGScene]: Fetching object " + assetID + " to asset server " + userAssetURL);
|
m_log.Debug("[HGScene]: Fetching object " + assetID + " from asset server " + userAssetURL);
|
||||||
AssetBase asset = FetchAsset(userAssetURL, assetID);
|
AssetBase asset = FetchAsset(userAssetURL, assetID);
|
||||||
|
|
||||||
if (asset != null)
|
if (asset != null)
|
||||||
{
|
{
|
||||||
m_log.Debug("[HGScene]: Successfully fetched item from remote asset server " + userAssetURL);
|
|
||||||
|
|
||||||
// OK, now fetch the inside.
|
// OK, now fetch the inside.
|
||||||
Dictionary<UUID, int> ids = new Dictionary<UUID, int>();
|
Dictionary<UUID, int> ids = new Dictionary<UUID, int>();
|
||||||
HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, userAssetURL);
|
HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, userAssetURL);
|
||||||
uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
|
uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
|
||||||
foreach (UUID uuid in ids.Keys)
|
foreach (UUID uuid in ids.Keys)
|
||||||
FetchAsset(userAssetURL, uuid);
|
FetchAsset(userAssetURL, uuid);
|
||||||
|
|
||||||
|
m_log.DebugFormat("[HGScene]: Successfully fetched asset {0} from asset server {1}", asset.ID, userAssetURL);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_log.Warn("[HGScene]: Could not fetch asset from remote asset server " + userAssetURL);
|
m_log.Warn("[HGScene]: Could not fetch asset from remote asset server " + userAssetURL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_log.Warn("[HGScene]: Unable to locate foreign user's asset server");
|
m_log.Debug("[HGScene]: user's asset server is the local region's asset server");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//public InventoryItemBase Get(InventoryItemBase item, UUID rootFolder, CachedUserInfo userInfo)
|
//public InventoryItemBase Get(InventoryItemBase item, UUID rootFolder, CachedUserInfo userInfo)
|
||||||
|
@ -224,14 +224,12 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
|
||||||
//}
|
//}
|
||||||
|
|
||||||
public void Post(UUID assetID, UUID ownerID)
|
public void Post(UUID assetID, UUID ownerID)
|
||||||
{
|
|
||||||
if (!HyperlinkService.IsLocalUser(ownerID))
|
|
||||||
{
|
{
|
||||||
// Post the item from the local AssetCache onto the remote asset server
|
// Post the item from the local AssetCache onto the remote asset server
|
||||||
// and place an entry in m_assetMap
|
// and place an entry in m_assetMap
|
||||||
|
|
||||||
string userAssetURL = UserAssetURL(ownerID);
|
string userAssetURL = HyperlinkAssets.GetUserAssetServer(ownerID);
|
||||||
if (userAssetURL != null)
|
if ((userAssetURL != string.Empty) && (userAssetURL != HyperlinkAssets.GetSimAssetServer()))
|
||||||
{
|
{
|
||||||
m_log.Debug("[HGScene]: Posting object " + assetID + " to asset server " + userAssetURL);
|
m_log.Debug("[HGScene]: Posting object " + assetID + " to asset server " + userAssetURL);
|
||||||
AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
|
AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
|
||||||
|
@ -243,27 +241,23 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
|
||||||
foreach (UUID uuid in ids.Keys)
|
foreach (UUID uuid in ids.Keys)
|
||||||
{
|
{
|
||||||
asset = m_scene.AssetService.Get(uuid.ToString());
|
asset = m_scene.AssetService.Get(uuid.ToString());
|
||||||
if (asset != null)
|
if (asset == null)
|
||||||
m_log.DebugFormat("[HGScene]: Posting {0} {1}", asset.Type.ToString(), asset.Name);
|
|
||||||
else
|
|
||||||
m_log.DebugFormat("[HGScene]: Could not find asset {0}", uuid);
|
m_log.DebugFormat("[HGScene]: Could not find asset {0}", uuid);
|
||||||
|
else
|
||||||
PostAsset(userAssetURL, asset);
|
PostAsset(userAssetURL, asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ids.Count > 0) // maybe it succeeded...
|
// maybe all pieces got there...
|
||||||
m_log.DebugFormat("[HGScene]: Successfully posted item {0} to remote asset server {1}", assetID, userAssetURL);
|
m_log.DebugFormat("[HGScene]: Successfully posted item {0} to asset server {1}", assetID, userAssetURL);
|
||||||
else
|
|
||||||
m_log.WarnFormat("[HGScene]: Could not post asset {0} to remote asset server {1}", assetID, userAssetURL);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_log.Debug("[HGScene]: Something wrong with asset, it could not be found");
|
m_log.DebugFormat("[HGScene]: Something wrong with asset {0}, it could not be found", assetID);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_log.Warn("[HGScene]: Unable to locate foreign user's asset server");
|
m_log.Debug("[HGScene]: user's asset server is local region's asset server");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ using OpenMetaverse;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Framework.Communications;
|
using OpenSim.Framework.Communications;
|
||||||
using OpenSim.Framework.Communications.Cache;
|
using OpenSim.Framework.Communications.Cache;
|
||||||
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
|
||||||
namespace OpenSim.Region.Framework.Scenes.Hypergrid
|
namespace OpenSim.Region.Framework.Scenes.Hypergrid
|
||||||
{
|
{
|
||||||
|
@ -41,6 +42,21 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
private HGAssetMapper m_assMapper;
|
private HGAssetMapper m_assMapper;
|
||||||
|
public HGAssetMapper AssetMapper
|
||||||
|
{
|
||||||
|
get { return m_assMapper; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private IHyperAssetService m_hyper;
|
||||||
|
private IHyperAssetService HyperAssets
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (m_hyper == null)
|
||||||
|
m_hyper = RequestModuleInterface<IHyperAssetService>();
|
||||||
|
return m_hyper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -140,6 +156,16 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver)
|
||||||
|
{
|
||||||
|
string userAssetServer = HyperAssets.GetUserAssetServer(sender);
|
||||||
|
if ((userAssetServer != string.Empty) && (userAssetServer != HyperAssets.GetSimAssetServer()))
|
||||||
|
m_assMapper.Get(item.AssetID, sender);
|
||||||
|
|
||||||
|
userAssetServer = HyperAssets.GetUserAssetServer(receiver);
|
||||||
|
if ((userAssetServer != string.Empty) && (userAssetServer != HyperAssets.GetSimAssetServer()))
|
||||||
|
m_assMapper.Post(item.AssetID, receiver);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
|
@ -408,7 +408,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
public virtual InventoryItemBase GiveInventoryItem(
|
public virtual InventoryItemBase GiveInventoryItem(
|
||||||
UUID recipient, UUID senderId, UUID itemId, UUID recipientFolderId)
|
UUID recipient, UUID senderId, UUID itemId, UUID recipientFolderId)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Scene.Inventory.cs: GiveInventoryItem");
|
//Console.WriteLine("Scene.Inventory.cs: GiveInventoryItem");
|
||||||
|
|
||||||
InventoryItemBase item = new InventoryItemBase(itemId, senderId);
|
InventoryItemBase item = new InventoryItemBase(itemId, senderId);
|
||||||
item = InventoryService.GetItem(item);
|
item = InventoryService.GetItem(item);
|
||||||
|
@ -472,7 +472,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
itemCopy.SalePrice = item.SalePrice;
|
itemCopy.SalePrice = item.SalePrice;
|
||||||
itemCopy.SaleType = item.SaleType;
|
itemCopy.SaleType = item.SaleType;
|
||||||
|
|
||||||
InventoryService.AddItem(itemCopy);
|
if (InventoryService.AddItem(itemCopy))
|
||||||
|
TransferInventoryAssets(itemCopy, senderId, recipient);
|
||||||
|
|
||||||
if (!Permissions.BypassPermissions())
|
if (!Permissions.BypassPermissions())
|
||||||
{
|
{
|
||||||
|
@ -494,6 +495,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Give an entire inventory folder from one user to another. The entire contents (including all descendent
|
/// Give an entire inventory folder from one user to another. The entire contents (including all descendent
|
||||||
/// folders) is given.
|
/// folders) is given.
|
||||||
|
|
|
@ -391,6 +391,32 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProcessViewerEffect(IClientAPI remoteClient, List<ViewerEffectEventHandlerArg> args)
|
||||||
|
{
|
||||||
|
// TODO: don't create new blocks if recycling an old packet
|
||||||
|
List<ViewerEffectPacket.EffectBlock> effectBlock = new List<ViewerEffectPacket.EffectBlock>();
|
||||||
|
for (int i = 0; i < args.Count; i++)
|
||||||
|
{
|
||||||
|
ViewerEffectPacket.EffectBlock effect = new ViewerEffectPacket.EffectBlock();
|
||||||
|
effect.AgentID = args[i].AgentID;
|
||||||
|
effect.Color = args[i].Color;
|
||||||
|
effect.Duration = args[i].Duration;
|
||||||
|
effect.ID = args[i].ID;
|
||||||
|
effect.Type = args[i].Type;
|
||||||
|
effect.TypeData = args[i].TypeData;
|
||||||
|
effectBlock.Add(effect);
|
||||||
|
}
|
||||||
|
ViewerEffectPacket.EffectBlock[] effectBlockArray = effectBlock.ToArray();
|
||||||
|
|
||||||
|
ClientManager.ForEach(
|
||||||
|
delegate(IClientAPI client)
|
||||||
|
{
|
||||||
|
if (client.AgentId != remoteClient.AgentId)
|
||||||
|
client.SendViewerEffect(effectBlockArray);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handle a fetch inventory request from the client
|
/// Handle a fetch inventory request from the client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -118,6 +118,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
|
private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
|
||||||
|
|
||||||
|
private Dictionary<UUID, SceneObjectGroup> m_groupsWithTargets = new Dictionary<UUID, SceneObjectGroup>();
|
||||||
|
|
||||||
protected string m_simulatorVersion = "OpenSimulator Server";
|
protected string m_simulatorVersion = "OpenSimulator Server";
|
||||||
|
|
||||||
protected ModuleLoader m_moduleLoader;
|
protected ModuleLoader m_moduleLoader;
|
||||||
|
@ -246,8 +248,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
private int m_update_physics = 1;
|
private int m_update_physics = 1;
|
||||||
private int m_update_entitymovement = 1;
|
private int m_update_entitymovement = 1;
|
||||||
private int m_update_entities = 1; // Run through all objects checking for updates
|
private int m_update_objects = 1; // Update objects which have scheduled themselves for updates
|
||||||
private int m_update_entitiesquick = 200; // Run through objects that have scheduled updates checking for updates
|
|
||||||
private int m_update_presences = 1; // Update scene presence movements
|
private int m_update_presences = 1; // Update scene presence movements
|
||||||
private int m_update_events = 1;
|
private int m_update_events = 1;
|
||||||
private int m_update_backup = 200;
|
private int m_update_backup = 200;
|
||||||
|
@ -867,7 +868,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
Thread.Sleep(500);
|
Thread.Sleep(500);
|
||||||
|
|
||||||
// Stop all client threads.
|
// Stop all client threads.
|
||||||
ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(true); });
|
ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(); });
|
||||||
|
|
||||||
// Stop updating the scene objects and agents.
|
// Stop updating the scene objects and agents.
|
||||||
//m_heartbeatTimer.Close();
|
//m_heartbeatTimer.Close();
|
||||||
|
@ -979,28 +980,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
maintc = Environment.TickCount;
|
maintc = Environment.TickCount;
|
||||||
|
|
||||||
TimeSpan SinceLastFrame = DateTime.Now - m_lastupdate;
|
TimeSpan SinceLastFrame = DateTime.Now - m_lastupdate;
|
||||||
// Aquire a lock so only one update call happens at once
|
|
||||||
//updateLock.WaitOne();
|
|
||||||
float physicsFPS = 0;
|
float physicsFPS = 0;
|
||||||
//m_log.Info("sadfadf" + m_neighbours.Count.ToString());
|
|
||||||
int agentsInScene = m_sceneGraph.GetRootAgentCount() + m_sceneGraph.GetChildAgentCount();
|
|
||||||
|
|
||||||
if (agentsInScene > 21)
|
|
||||||
{
|
|
||||||
if (m_update_entities == 1)
|
|
||||||
{
|
|
||||||
m_update_entities = 5;
|
|
||||||
StatsReporter.SetUpdateMS(6000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (m_update_entities == 5)
|
|
||||||
{
|
|
||||||
m_update_entities = 1;
|
|
||||||
StatsReporter.SetUpdateMS(3000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
frameMS = Environment.TickCount;
|
frameMS = Environment.TickCount;
|
||||||
try
|
try
|
||||||
|
@ -1013,30 +993,17 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_frame = 0;
|
m_frame = 0;
|
||||||
|
|
||||||
otherMS = Environment.TickCount;
|
otherMS = Environment.TickCount;
|
||||||
// run through all entities looking for updates (slow)
|
|
||||||
if (m_frame % m_update_entities == 0)
|
|
||||||
{
|
|
||||||
/* // Adam Experimental
|
|
||||||
if (m_updateEntitiesThread == null)
|
|
||||||
{
|
|
||||||
m_updateEntitiesThread = new Thread(m_sceneGraph.UpdateEntities);
|
|
||||||
|
|
||||||
ThreadTracker.Add(m_updateEntitiesThread);
|
// Check if any objects have reached their targets
|
||||||
}
|
CheckAtTargets();
|
||||||
|
|
||||||
if (m_updateEntitiesThread.ThreadState == ThreadState.Stopped)
|
// Update SceneObjectGroups that have scheduled themselves for updates
|
||||||
m_updateEntitiesThread.Start();
|
// Objects queue their updates onto all scene presences
|
||||||
*/
|
if (m_frame % m_update_objects == 0)
|
||||||
|
m_sceneGraph.UpdateObjectGroups();
|
||||||
|
|
||||||
m_sceneGraph.UpdateEntities();
|
// Run through all ScenePresences looking for updates
|
||||||
}
|
// Presence updates and queued object updates for each presence are sent to clients
|
||||||
|
|
||||||
// run through entities that have scheduled themselves for
|
|
||||||
// updates looking for updates(faster)
|
|
||||||
if (m_frame % m_update_entitiesquick == 0)
|
|
||||||
m_sceneGraph.ProcessUpdates();
|
|
||||||
|
|
||||||
// Run through scenepresences looking for updates
|
|
||||||
if (m_frame % m_update_presences == 0)
|
if (m_frame % m_update_presences == 0)
|
||||||
m_sceneGraph.UpdatePresences();
|
m_sceneGraph.UpdatePresences();
|
||||||
|
|
||||||
|
@ -1140,6 +1107,31 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void AddGroupTarget(SceneObjectGroup grp)
|
||||||
|
{
|
||||||
|
lock(m_groupsWithTargets)
|
||||||
|
m_groupsWithTargets[grp.UUID] = grp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveGroupTarget(SceneObjectGroup grp)
|
||||||
|
{
|
||||||
|
lock(m_groupsWithTargets)
|
||||||
|
m_groupsWithTargets.Remove(grp.UUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckAtTargets()
|
||||||
|
{
|
||||||
|
lock (m_groupsWithTargets)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<UUID, SceneObjectGroup> kvp in m_groupsWithTargets)
|
||||||
|
{
|
||||||
|
kvp.Value.checkAtTargets();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send out simstats data to all clients
|
/// Send out simstats data to all clients
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1186,10 +1178,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
if (!m_backingup)
|
if (!m_backingup)
|
||||||
{
|
{
|
||||||
m_backingup = true;
|
m_backingup = true;
|
||||||
Thread backupthread = new Thread(Backup);
|
|
||||||
backupthread.Name = "BackupWriter";
|
System.ComponentModel.BackgroundWorker backupWorker = new System.ComponentModel.BackgroundWorker();
|
||||||
backupthread.IsBackground = true;
|
backupWorker.DoWork += delegate(object sender, System.ComponentModel.DoWorkEventArgs e) { Backup(); };
|
||||||
backupthread.Start();
|
backupWorker.RunWorkerAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1780,36 +1772,87 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
Vector3 pos = attemptedPosition;
|
Vector3 pos = attemptedPosition;
|
||||||
|
|
||||||
|
int changeX = 1;
|
||||||
|
int changeY = 1;
|
||||||
|
|
||||||
if (TestBorderCross(attemptedPosition + WestCross, Cardinals.W))
|
if (TestBorderCross(attemptedPosition + WestCross, Cardinals.W))
|
||||||
{
|
{
|
||||||
if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
|
if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
|
||||||
{
|
{
|
||||||
//Border crossedBorderx = GetCrossedBorder(attemptedPosition,Cardinals.W);
|
|
||||||
//Border crossedBordery = GetCrossedBorder(attemptedPosition, Cardinals.S);
|
Border crossedBorderx = GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
|
||||||
//(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
|
|
||||||
|
if (crossedBorderx.BorderLine.Z > 0)
|
||||||
|
{
|
||||||
|
pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
|
||||||
|
changeX = (int)(crossedBorderx.BorderLine.Z /(int) Constants.RegionSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
pos.X = ((pos.X + Constants.RegionSize));
|
pos.X = ((pos.X + Constants.RegionSize));
|
||||||
|
|
||||||
|
Border crossedBordery = GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
|
||||||
|
//(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
|
||||||
|
|
||||||
|
if (crossedBordery.BorderLine.Z > 0)
|
||||||
|
{
|
||||||
|
pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
|
||||||
|
changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
pos.Y = ((pos.Y + Constants.RegionSize));
|
pos.Y = ((pos.Y + Constants.RegionSize));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
newRegionHandle
|
newRegionHandle
|
||||||
= Util.UIntsToLong((uint)((thisx - 1) * Constants.RegionSize),
|
= Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
|
||||||
(uint)((thisy - 1) * Constants.RegionSize));
|
(uint)((thisy - changeY) * Constants.RegionSize));
|
||||||
// x - 1
|
// x - 1
|
||||||
// y - 1
|
// y - 1
|
||||||
}
|
}
|
||||||
else if (TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
|
else if (TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
|
||||||
{
|
{
|
||||||
|
Border crossedBorderx = GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
|
||||||
|
|
||||||
|
if (crossedBorderx.BorderLine.Z > 0)
|
||||||
|
{
|
||||||
|
pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
|
||||||
|
changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
pos.X = ((pos.X + Constants.RegionSize));
|
pos.X = ((pos.X + Constants.RegionSize));
|
||||||
pos.Y = ((pos.Y - Constants.RegionSize));
|
|
||||||
|
|
||||||
|
Border crossedBordery = GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
|
||||||
|
//(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
|
||||||
|
|
||||||
|
if (crossedBordery.BorderLine.Z > 0)
|
||||||
|
{
|
||||||
|
pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
|
||||||
|
changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pos.Y = ((pos.Y + Constants.RegionSize));
|
||||||
|
|
||||||
newRegionHandle
|
newRegionHandle
|
||||||
= Util.UIntsToLong((uint)((thisx - 1) * Constants.RegionSize),
|
= Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
|
||||||
(uint)((thisy + 1) * Constants.RegionSize));
|
(uint)((thisy + changeY) * Constants.RegionSize));
|
||||||
// x - 1
|
// x - 1
|
||||||
// y + 1
|
// y + 1
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Border crossedBorderx = GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
|
||||||
|
|
||||||
|
if (crossedBorderx.BorderLine.Z > 0)
|
||||||
|
{
|
||||||
|
pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
|
||||||
|
changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
pos.X = ((pos.X + Constants.RegionSize));
|
pos.X = ((pos.X + Constants.RegionSize));
|
||||||
|
|
||||||
newRegionHandle
|
newRegionHandle
|
||||||
= Util.UIntsToLong((uint) ((thisx - 1)*Constants.RegionSize),
|
= Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
|
||||||
(uint) (thisy*Constants.RegionSize));
|
(uint) (thisy*Constants.RegionSize));
|
||||||
// x - 1
|
// x - 1
|
||||||
}
|
}
|
||||||
|
@ -1818,11 +1861,23 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
|
if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
|
||||||
{
|
{
|
||||||
|
|
||||||
pos.X = ((pos.X - Constants.RegionSize));
|
pos.X = ((pos.X - Constants.RegionSize));
|
||||||
|
Border crossedBordery = GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
|
||||||
|
//(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
|
||||||
|
|
||||||
|
if (crossedBordery.BorderLine.Z > 0)
|
||||||
|
{
|
||||||
|
pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
|
||||||
|
changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
pos.Y = ((pos.Y + Constants.RegionSize));
|
pos.Y = ((pos.Y + Constants.RegionSize));
|
||||||
|
|
||||||
|
|
||||||
newRegionHandle
|
newRegionHandle
|
||||||
= Util.UIntsToLong((uint)((thisx + 1) * Constants.RegionSize),
|
= Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
|
||||||
(uint)((thisy - 1) * Constants.RegionSize));
|
(uint)((thisy - changeY) * Constants.RegionSize));
|
||||||
// x + 1
|
// x + 1
|
||||||
// y - 1
|
// y - 1
|
||||||
}
|
}
|
||||||
|
@ -1831,8 +1886,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
pos.X = ((pos.X - Constants.RegionSize));
|
pos.X = ((pos.X - Constants.RegionSize));
|
||||||
pos.Y = ((pos.Y - Constants.RegionSize));
|
pos.Y = ((pos.Y - Constants.RegionSize));
|
||||||
newRegionHandle
|
newRegionHandle
|
||||||
= Util.UIntsToLong((uint)((thisx + 1) * Constants.RegionSize),
|
= Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
|
||||||
(uint)((thisy + 1) * Constants.RegionSize));
|
(uint)((thisy + changeY) * Constants.RegionSize));
|
||||||
// x + 1
|
// x + 1
|
||||||
// y + 1
|
// y + 1
|
||||||
}
|
}
|
||||||
|
@ -1840,16 +1895,26 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
pos.X = ((pos.X - Constants.RegionSize));
|
pos.X = ((pos.X - Constants.RegionSize));
|
||||||
newRegionHandle
|
newRegionHandle
|
||||||
= Util.UIntsToLong((uint) ((thisx + 1)*Constants.RegionSize),
|
= Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
|
||||||
(uint) (thisy*Constants.RegionSize));
|
(uint) (thisy*Constants.RegionSize));
|
||||||
// x + 1
|
// x + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
|
else if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
|
||||||
{
|
{
|
||||||
|
Border crossedBordery = GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
|
||||||
|
//(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
|
||||||
|
|
||||||
|
if (crossedBordery.BorderLine.Z > 0)
|
||||||
|
{
|
||||||
|
pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
|
||||||
|
changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
pos.Y = ((pos.Y + Constants.RegionSize));
|
pos.Y = ((pos.Y + Constants.RegionSize));
|
||||||
|
|
||||||
newRegionHandle
|
newRegionHandle
|
||||||
= Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - 1) * Constants.RegionSize));
|
= Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - changeY) * Constants.RegionSize));
|
||||||
// y - 1
|
// y - 1
|
||||||
}
|
}
|
||||||
else if (TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
|
else if (TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
|
||||||
|
@ -1857,7 +1922,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
pos.Y = ((pos.Y - Constants.RegionSize));
|
pos.Y = ((pos.Y - Constants.RegionSize));
|
||||||
newRegionHandle
|
newRegionHandle
|
||||||
= Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + 1) * Constants.RegionSize));
|
= Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + changeY) * Constants.RegionSize));
|
||||||
// y + 1
|
// y + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2363,6 +2428,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <param name="client"></param>
|
/// <param name="client"></param>
|
||||||
public override void AddNewClient(IClientAPI client)
|
public override void AddNewClient(IClientAPI client)
|
||||||
{
|
{
|
||||||
|
ClientManager.Add(client);
|
||||||
|
|
||||||
CheckHeartbeat();
|
CheckHeartbeat();
|
||||||
SubscribeToClientEvents(client);
|
SubscribeToClientEvents(client);
|
||||||
ScenePresence presence;
|
ScenePresence presence;
|
||||||
|
@ -2572,6 +2639,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
public virtual void SubscribeToClientNetworkEvents(IClientAPI client)
|
public virtual void SubscribeToClientNetworkEvents(IClientAPI client)
|
||||||
{
|
{
|
||||||
client.OnNetworkStatsUpdate += StatsReporter.AddPacketsStats;
|
client.OnNetworkStatsUpdate += StatsReporter.AddPacketsStats;
|
||||||
|
client.OnViewerEffect += ProcessViewerEffect;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void UnsubscribeToClientEvents(IClientAPI client)
|
protected virtual void UnsubscribeToClientEvents(IClientAPI client)
|
||||||
|
@ -2726,11 +2794,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
public virtual void UnSubscribeToClientNetworkEvents(IClientAPI client)
|
public virtual void UnSubscribeToClientNetworkEvents(IClientAPI client)
|
||||||
{
|
{
|
||||||
client.OnNetworkStatsUpdate -= StatsReporter.AddPacketsStats;
|
client.OnNetworkStatsUpdate -= StatsReporter.AddPacketsStats;
|
||||||
|
client.OnViewerEffect -= ProcessViewerEffect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Teleport an avatar to their home region
|
/// Teleport an avatar to their home region
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -3003,7 +3069,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
agentTransactions.RemoveAgentAssetTransactions(agentID);
|
agentTransactions.RemoveAgentAssetTransactions(agentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the avatar from the scene
|
||||||
m_sceneGraph.RemoveScenePresence(agentID);
|
m_sceneGraph.RemoveScenePresence(agentID);
|
||||||
|
ClientManager.Remove(agentID);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -3052,16 +3120,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Closes all endpoints with the circuitcode provided.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="circuitcode">Circuit Code of the endpoint to close</param>
|
|
||||||
public override void CloseAllAgents(uint circuitcode)
|
|
||||||
{
|
|
||||||
// Called by ClientView to kill all circuit codes
|
|
||||||
ClientManager.CloseAllAgents(circuitcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Inform all other ScenePresences on this Scene that someone else has changed position on the minimap.
|
/// Inform all other ScenePresences on this Scene that someone else has changed position on the minimap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -3383,7 +3441,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
loggingOffUser.ControllingClient.Kick(message);
|
loggingOffUser.ControllingClient.Kick(message);
|
||||||
// Give them a second to receive the message!
|
// Give them a second to receive the message!
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
loggingOffUser.ControllingClient.Close(true);
|
loggingOffUser.ControllingClient.Close();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3554,7 +3612,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
presence.ControllingClient.SendShutdownConnectionNotice();
|
presence.ControllingClient.SendShutdownConnectionNotice();
|
||||||
}
|
}
|
||||||
|
|
||||||
presence.ControllingClient.Close(true);
|
presence.ControllingClient.Close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,8 +196,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <param name="agentID"></param>
|
/// <param name="agentID"></param>
|
||||||
public abstract void RemoveClient(UUID agentID);
|
public abstract void RemoveClient(UUID agentID);
|
||||||
|
|
||||||
public abstract void CloseAllAgents(uint circuitcode);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -77,7 +77,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
protected RegionInfo m_regInfo;
|
protected RegionInfo m_regInfo;
|
||||||
protected Scene m_parentScene;
|
protected Scene m_parentScene;
|
||||||
protected Dictionary<UUID, EntityBase> m_updateList = new Dictionary<UUID, EntityBase>();
|
protected Dictionary<UUID, SceneObjectGroup> m_updateList = new Dictionary<UUID, SceneObjectGroup>();
|
||||||
protected int m_numRootAgents = 0;
|
protected int m_numRootAgents = 0;
|
||||||
protected int m_numPrim = 0;
|
protected int m_numPrim = 0;
|
||||||
protected int m_numChildAgents = 0;
|
protected int m_numChildAgents = 0;
|
||||||
|
@ -155,16 +155,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected internal void UpdateEntities()
|
|
||||||
{
|
|
||||||
List<EntityBase> updateEntities = GetEntities();
|
|
||||||
|
|
||||||
foreach (EntityBase entity in updateEntities)
|
|
||||||
{
|
|
||||||
entity.Update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected internal void UpdatePresences()
|
protected internal void UpdatePresences()
|
||||||
{
|
{
|
||||||
List<ScenePresence> updateScenePresences = GetScenePresences();
|
List<ScenePresence> updateScenePresences = GetScenePresences();
|
||||||
|
@ -365,12 +355,12 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add an entity to the list of prims to process on the next update
|
/// Add an object to the list of prims to process on the next update
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">
|
/// <param name="obj">
|
||||||
/// A <see cref="EntityBase"/>
|
/// A <see cref="SceneObjectGroup"/>
|
||||||
/// </param>
|
/// </param>
|
||||||
protected internal void AddToUpdateList(EntityBase obj)
|
protected internal void AddToUpdateList(SceneObjectGroup obj)
|
||||||
{
|
{
|
||||||
lock (m_updateList)
|
lock (m_updateList)
|
||||||
{
|
{
|
||||||
|
@ -381,18 +371,18 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Process all pending updates
|
/// Process all pending updates
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected internal void ProcessUpdates()
|
protected internal void UpdateObjectGroups()
|
||||||
{
|
{
|
||||||
Dictionary<UUID, EntityBase> updates;
|
Dictionary<UUID, SceneObjectGroup> updates;
|
||||||
// Some updates add more updates to the updateList.
|
// Some updates add more updates to the updateList.
|
||||||
// Get the current list of updates and clear the list before iterating
|
// Get the current list of updates and clear the list before iterating
|
||||||
lock (m_updateList)
|
lock (m_updateList)
|
||||||
{
|
{
|
||||||
updates = new Dictionary<UUID, EntityBase>(m_updateList);
|
updates = new Dictionary<UUID, SceneObjectGroup>(m_updateList);
|
||||||
m_updateList.Clear();
|
m_updateList.Clear();
|
||||||
}
|
}
|
||||||
// Go through all timers
|
// Go through all updates
|
||||||
foreach (KeyValuePair<UUID, EntityBase> kvp in updates)
|
foreach (KeyValuePair<UUID, SceneObjectGroup> kvp in updates)
|
||||||
{
|
{
|
||||||
// Don't abort the whole update if one entity happens to give us an exception.
|
// Don't abort the whole update if one entity happens to give us an exception.
|
||||||
try
|
try
|
||||||
|
|
|
@ -1241,6 +1241,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
lock (m_targets)
|
lock (m_targets)
|
||||||
m_targets.Clear();
|
m_targets.Clear();
|
||||||
|
m_scene.RemoveGroupTarget(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduleGroupForFullUpdate();
|
ScheduleGroupForFullUpdate();
|
||||||
|
@ -1871,12 +1872,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_rootPart.UpdateFlag = 1;
|
m_rootPart.UpdateFlag = 1;
|
||||||
lastPhysGroupPos = AbsolutePosition;
|
lastPhysGroupPos = AbsolutePosition;
|
||||||
}
|
}
|
||||||
//foreach (SceneObjectPart part in m_parts.Values)
|
|
||||||
//{
|
|
||||||
//if (part.UpdateFlag == 0) part.UpdateFlag = 1;
|
|
||||||
//}
|
|
||||||
|
|
||||||
checkAtTargets();
|
|
||||||
|
|
||||||
if (UsePhysics && ((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1)
|
if (UsePhysics && ((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1)
|
||||||
|| (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1)
|
|| (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1)
|
||||||
|
@ -3126,6 +3121,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
m_targets.Add(handle, waypoint);
|
m_targets.Add(handle, waypoint);
|
||||||
}
|
}
|
||||||
|
m_scene.AddGroupTarget(this);
|
||||||
return (int)handle;
|
return (int)handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3133,12 +3129,13 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
lock (m_targets)
|
lock (m_targets)
|
||||||
{
|
{
|
||||||
if (m_targets.ContainsKey((uint)handle))
|
|
||||||
m_targets.Remove((uint)handle);
|
m_targets.Remove((uint)handle);
|
||||||
|
if (m_targets.Count == 0)
|
||||||
|
m_scene.RemoveGroupTarget(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAtTargets()
|
public void checkAtTargets()
|
||||||
{
|
{
|
||||||
if (m_scriptListens_atTarget || m_scriptListens_notAtTarget)
|
if (m_scriptListens_atTarget || m_scriptListens_notAtTarget)
|
||||||
{
|
{
|
||||||
|
|
|
@ -61,11 +61,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void CloseAllAgents(uint circuitcode)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OtherRegionUp(GridRegion otherRegion)
|
public override void OtherRegionUp(GridRegion otherRegion)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
|
@ -64,7 +64,6 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView
|
||||||
void user_OnIRCReady(IRCClientView cv)
|
void user_OnIRCReady(IRCClientView cv)
|
||||||
{
|
{
|
||||||
m_log.Info("[IRCd] Adding user...");
|
m_log.Info("[IRCd] Adding user...");
|
||||||
m_scene.ClientManager.Add(cv.CircuitCode, cv);
|
|
||||||
cv.Start();
|
cv.Start();
|
||||||
m_log.Info("[IRCd] Added user to Scene");
|
m_log.Info("[IRCd] Added user to Scene");
|
||||||
}
|
}
|
||||||
|
|
|
@ -634,6 +634,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
|
||||||
{
|
{
|
||||||
get { return (uint)Util.RandomClass.Next(0,int.MaxValue); }
|
get { return (uint)Util.RandomClass.Next(0,int.MaxValue); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IPEndPoint RemoteEndPoint
|
||||||
|
{
|
||||||
|
get { return (IPEndPoint)m_client.Client.RemoteEndPoint; }
|
||||||
|
}
|
||||||
|
|
||||||
#pragma warning disable 67
|
#pragma warning disable 67
|
||||||
public event GenericMessage OnGenericMessage;
|
public event GenericMessage OnGenericMessage;
|
||||||
public event ImprovedInstantMessage OnInstantMessage;
|
public event ImprovedInstantMessage OnInstantMessage;
|
||||||
|
@ -843,7 +849,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close(bool ShutdownCircuit)
|
public void Close()
|
||||||
{
|
{
|
||||||
Disconnect();
|
Disconnect();
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,7 +183,8 @@ namespace OpenSim.Region.OptionalModules.ContentManagement
|
||||||
public virtual void HideFromAll()
|
public virtual void HideFromAll()
|
||||||
{
|
{
|
||||||
foreach (SceneObjectPart part in m_Entity.Children.Values)
|
foreach (SceneObjectPart part in m_Entity.Children.Values)
|
||||||
m_Entity.Scene.ClientManager.ForEachClient(delegate(IClientAPI controller)
|
m_Entity.Scene.ClientManager.ForEach(
|
||||||
|
delegate(IClientAPI controller)
|
||||||
{ controller.SendKillObject(m_Entity.RegionHandle, part.LocalId); }
|
{ controller.SendKillObject(m_Entity.RegionHandle, part.LocalId); }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -201,7 +202,8 @@ namespace OpenSim.Region.OptionalModules.ContentManagement
|
||||||
|
|
||||||
public void SendFullUpdateToAll()
|
public void SendFullUpdateToAll()
|
||||||
{
|
{
|
||||||
m_Entity.Scene.ClientManager.ForEachClient(delegate(IClientAPI controller)
|
m_Entity.Scene.ClientManager.ForEach(
|
||||||
|
delegate(IClientAPI controller)
|
||||||
{ m_Entity.SendFullUpdateToClient(controller); }
|
{ m_Entity.SendFullUpdateToClient(controller); }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -825,7 +825,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close(bool ShutdownCircuit)
|
public void Close()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -838,11 +838,21 @@ namespace OpenSim.Region.OptionalModules.World.NPC
|
||||||
}
|
}
|
||||||
|
|
||||||
private uint m_circuitCode;
|
private uint m_circuitCode;
|
||||||
|
private IPEndPoint m_remoteEndPoint;
|
||||||
|
|
||||||
public uint CircuitCode
|
public uint CircuitCode
|
||||||
{
|
{
|
||||||
get { return m_circuitCode; }
|
get { return m_circuitCode; }
|
||||||
set { m_circuitCode = value; }
|
set
|
||||||
|
{
|
||||||
|
m_circuitCode = value;
|
||||||
|
m_remoteEndPoint = new IPEndPoint(IPAddress.Loopback, (ushort)m_circuitCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPEndPoint RemoteEndPoint
|
||||||
|
{
|
||||||
|
get { return m_remoteEndPoint; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message)
|
public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message)
|
||||||
|
|
|
@ -155,7 +155,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC
|
||||||
NPCAvatar npcAvatar = new NPCAvatar(p_firstname, p_lastname, p_position, p_scene);
|
NPCAvatar npcAvatar = new NPCAvatar(p_firstname, p_lastname, p_position, p_scene);
|
||||||
npcAvatar.CircuitCode = (uint) Util.RandomClass.Next(0, int.MaxValue);
|
npcAvatar.CircuitCode = (uint) Util.RandomClass.Next(0, int.MaxValue);
|
||||||
|
|
||||||
p_scene.ClientManager.Add(npcAvatar.CircuitCode, npcAvatar);
|
|
||||||
p_scene.AddNewClient(npcAvatar);
|
p_scene.AddNewClient(npcAvatar);
|
||||||
|
|
||||||
ScenePresence sp;
|
ScenePresence sp;
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace PrimMesher
|
||||||
|
|
||||||
public Quat Identity()
|
public Quat Identity()
|
||||||
{
|
{
|
||||||
return new Quat(0.0f, 0.0f, 0.0f, 1.1f);
|
return new Quat(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float Length()
|
public float Length()
|
||||||
|
|
|
@ -863,7 +863,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
World.Entities.TryGetValue(objecUUID, out SensedObject);
|
World.Entities.TryGetValue(objecUUID, out SensedObject);
|
||||||
|
|
||||||
if (SensedObject == null)
|
if (SensedObject == null)
|
||||||
|
{
|
||||||
|
IGroupsModule groups = World.RequestModuleInterface<IGroupsModule>();
|
||||||
|
if (groups != null)
|
||||||
|
{
|
||||||
|
GroupRecord gr = groups.GetGroupRecord(objecUUID);
|
||||||
|
if (gr != null)
|
||||||
|
return gr.GroupName;
|
||||||
|
}
|
||||||
return String.Empty;
|
return String.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
return SensedObject.Name;
|
return SensedObject.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,12 +64,17 @@ namespace OpenSim.Services.AssetService
|
||||||
string loaderArgs = assetConfig.GetString("AssetLoaderArgs",
|
string loaderArgs = assetConfig.GetString("AssetLoaderArgs",
|
||||||
String.Empty);
|
String.Empty);
|
||||||
|
|
||||||
|
bool assetLoaderEnabled = assetConfig.GetBoolean("AssetLoaderEnabled", true);
|
||||||
|
|
||||||
|
if (assetLoaderEnabled)
|
||||||
|
{
|
||||||
m_log.InfoFormat("[ASSET]: Loading default asset set from {0}", loaderArgs);
|
m_log.InfoFormat("[ASSET]: Loading default asset set from {0}", loaderArgs);
|
||||||
m_AssetLoader.ForEachDefaultXmlAsset(loaderArgs,
|
m_AssetLoader.ForEachDefaultXmlAsset(loaderArgs,
|
||||||
delegate(AssetBase a)
|
delegate(AssetBase a)
|
||||||
{
|
{
|
||||||
Store(a);
|
Store(a);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
m_log.Info("[ASSET CONNECTOR]: Local asset service enabled");
|
m_log.Info("[ASSET CONNECTOR]: Local asset service enabled");
|
||||||
}
|
}
|
||||||
|
|
|
@ -298,7 +298,7 @@ namespace OpenSim.Services.Connectors
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetBase asset = asset = m_Cache.Get(assetID.ToString());
|
AssetBase asset = m_Cache.Get(assetID.ToString());
|
||||||
|
|
||||||
if (asset == null)
|
if (asset == null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -299,6 +299,7 @@ namespace OpenSim.Services.Connectors.Inventory
|
||||||
|
|
||||||
if (StringToUrlAndUserID(id, out url, out userID))
|
if (StringToUrlAndUserID(id, out url, out userID))
|
||||||
{
|
{
|
||||||
|
//m_log.DebugFormat("[HGInventory CONNECTOR]: calling {0}", url);
|
||||||
ISessionAuthInventoryService connector = GetConnector(url);
|
ISessionAuthInventoryService connector = GetConnector(url);
|
||||||
return connector.QueryItem(userID, item, sessionID);
|
return connector.QueryItem(userID, item, sessionID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ namespace OpenSim.Services.Connectors
|
||||||
LogManager.GetLogger(
|
LogManager.GetLogger(
|
||||||
MethodBase.GetCurrentMethod().DeclaringType);
|
MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
private string m_ServerURI = String.Empty;
|
// private string m_ServerURI = String.Empty;
|
||||||
|
|
||||||
public UserServicesConnector()
|
public UserServicesConnector()
|
||||||
{
|
{
|
||||||
|
@ -53,7 +53,7 @@ namespace OpenSim.Services.Connectors
|
||||||
|
|
||||||
public UserServicesConnector(string serverURI)
|
public UserServicesConnector(string serverURI)
|
||||||
{
|
{
|
||||||
m_ServerURI = serverURI.TrimEnd('/');
|
// m_ServerURI = serverURI.TrimEnd('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserServicesConnector(IConfigSource source)
|
public UserServicesConnector(IConfigSource source)
|
||||||
|
@ -78,7 +78,7 @@ namespace OpenSim.Services.Connectors
|
||||||
m_log.Error("[USER CONNECTOR]: No Server URI named in section UserService");
|
m_log.Error("[USER CONNECTOR]: No Server URI named in section UserService");
|
||||||
throw new Exception("User connector init error");
|
throw new Exception("User connector init error");
|
||||||
}
|
}
|
||||||
m_ServerURI = serviceURI;
|
//m_ServerURI = serviceURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName)
|
public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName)
|
||||||
|
|
|
@ -200,6 +200,12 @@ namespace OpenSim.Services.Interfaces
|
||||||
Maturity = ConvertFrom.RegionSettings.Maturity;
|
Maturity = ConvertFrom.RegionSettings.Maturity;
|
||||||
RegionSecret = ConvertFrom.regionSecret;
|
RegionSecret = ConvertFrom.regionSecret;
|
||||||
EstateOwner = ConvertFrom.EstateSettings.EstateOwner;
|
EstateOwner = ConvertFrom.EstateSettings.EstateOwner;
|
||||||
|
if (EstateOwner == UUID.Zero)
|
||||||
|
{
|
||||||
|
EstateOwner = ConvertFrom.MasterAvatarAssignedUUID;
|
||||||
|
ConvertFrom.EstateSettings.EstateOwner = EstateOwner;
|
||||||
|
ConvertFrom.EstateSettings.Save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GridRegion(GridRegion ConvertFrom)
|
public GridRegion(GridRegion ConvertFrom)
|
||||||
|
|
|
@ -393,6 +393,11 @@ namespace OpenSim.Tests.Common.Mock
|
||||||
set { m_circuitCode = value; }
|
set { m_circuitCode = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IPEndPoint RemoteEndPoint
|
||||||
|
{
|
||||||
|
get { return new IPEndPoint(IPAddress.Loopback, (ushort)m_circuitCode); }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -865,7 +870,7 @@ namespace OpenSim.Tests.Common.Mock
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close(bool ShutdownCircuit)
|
public void Close()
|
||||||
{
|
{
|
||||||
m_scene.RemoveClient(AgentId);
|
m_scene.RemoveClient(AgentId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
MICROSOFT PUBLIC LICENSE (Ms-PL)
|
||||||
|
|
||||||
|
This license governs use of the accompanying software. If you use the software,
|
||||||
|
you accept this license. If you do not accept the license, do not use the
|
||||||
|
software.
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
The terms "reproduce," "reproduction," "derivative works," and "distribution"
|
||||||
|
have the same meaning here as under U.S. copyright law.
|
||||||
|
|
||||||
|
A "contribution" is the original software, or any additions or changes to the
|
||||||
|
software.
|
||||||
|
|
||||||
|
A "contributor" is any person that distributes its contribution under this
|
||||||
|
license.
|
||||||
|
|
||||||
|
"Licensed patents" are a contributor's patent claims that read directly on its
|
||||||
|
contribution.
|
||||||
|
|
||||||
|
2. Grant of Rights
|
||||||
|
|
||||||
|
(A) Copyright Grant- Subject to the terms of this license, including the license
|
||||||
|
conditions and limitations in section 3, each contributor grants you a
|
||||||
|
non-exclusive, worldwide, royalty-free copyright license to reproduce its
|
||||||
|
contribution, prepare derivative works of its contribution, and distribute its
|
||||||
|
contribution or any derivative works that you create.
|
||||||
|
|
||||||
|
(B) Patent Grant- Subject to the terms of this license, including the license
|
||||||
|
conditions and limitations in section 3, each contributor grants you a
|
||||||
|
non-exclusive, worldwide, royalty-free license under its licensed patents to
|
||||||
|
make, have made, use, sell, offer for sale, import, and/or otherwise dispose of
|
||||||
|
its contribution in the software or derivative works of the contribution in the
|
||||||
|
software.
|
||||||
|
|
||||||
|
3. Conditions and Limitations
|
||||||
|
|
||||||
|
(A) No Trademark License- This license does not grant you rights to use any
|
||||||
|
contributors' name, logo, or trademarks.
|
||||||
|
|
||||||
|
(B) If you bring a patent claim against any contributor over patents that you
|
||||||
|
claim are infringed by the software, your patent license from such contributor
|
||||||
|
to the software ends automatically.
|
||||||
|
|
||||||
|
(C) If you distribute any portion of the software, you must retain all
|
||||||
|
copyright, patent, trademark, and attribution notices that are present in the
|
||||||
|
software.
|
||||||
|
|
||||||
|
(D) If you distribute any portion of the software in source code form, you may
|
||||||
|
do so only under this license by including a complete copy of this license with
|
||||||
|
your distribution. If you distribute any portion of the software in compiled or
|
||||||
|
object code form, you may only do so under a license that complies with this
|
||||||
|
license.
|
||||||
|
|
||||||
|
(E) The software is licensed "as-is." You bear the risk of using it. The
|
||||||
|
contributors give no express warranties, guarantees or conditions. You may have
|
||||||
|
additional consumer rights under your local laws which this license cannot
|
||||||
|
change. To the extent permitted under your local laws, the contributors exclude
|
||||||
|
the implied warranties of merchantability, fitness for a particular purpose and
|
||||||
|
non-infringement.
|
|
@ -0,0 +1,28 @@
|
||||||
|
Copyright (c) 1999/2000 JJ2000 Partners.
|
||||||
|
|
||||||
|
This software module was originally developed by Raphaël Grosbois and
|
||||||
|
Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||||
|
Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||||
|
Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||||
|
Centre France S.A) in the course of development of the JPEG2000
|
||||||
|
standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||||
|
software module is an implementation of a part of the JPEG 2000
|
||||||
|
Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||||
|
Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||||
|
Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||||
|
2000 Standard (Users) any of their rights under the copyright, not
|
||||||
|
including other intellectual property rights, for this software module
|
||||||
|
with respect to the usage by ISO/IEC and Users of this software module
|
||||||
|
or modifications thereof for use in hardware or software products
|
||||||
|
claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||||
|
this software module in hardware or software products are advised that
|
||||||
|
their use may infringe existing patents. The original developers of
|
||||||
|
this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||||
|
for use of this software module or modifications thereof. No license
|
||||||
|
or right to this software module is granted for non JPEG 2000 Standard
|
||||||
|
conforming products. JJ2000 Partners have full right to use this
|
||||||
|
software module for his/her own purpose, assign or donate this
|
||||||
|
software module to any third party and to inhibit third parties from
|
||||||
|
using this software module for non JPEG 2000 Standard conforming
|
||||||
|
products. This copyright notice must be included in all copies or
|
||||||
|
derivative works of this software module.
|
Binary file not shown.
|
@ -1,33 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<configuration>
|
|
||||||
<configSections>
|
|
||||||
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
|
|
||||||
</configSections>
|
|
||||||
<runtime>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="nunit.framework" publicKeyToken="96d09a1eb7f44a77" culture="Neutral" />
|
|
||||||
<bindingRedirect oldVersion="2.0.6.0" newVersion="2.4.6.0" />
|
|
||||||
<bindingRedirect oldVersion="2.1.4.0" newVersion="2.4.6.0" />
|
|
||||||
<bindingRedirect oldVersion="2.2.8.0" newVersion="2.4.6.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
</runtime>
|
|
||||||
<log4net>
|
|
||||||
<!-- A1 is set to be a ConsoleAppender -->
|
|
||||||
<appender name="A1" type="log4net.Appender.ConsoleAppender">
|
|
||||||
|
|
||||||
<!-- A1 uses PatternLayout -->
|
|
||||||
<layout type="log4net.Layout.PatternLayout">
|
|
||||||
<!-- Print the date in ISO 8601 format -->
|
|
||||||
<conversionPattern value="%date [%thread] %-5level %logger %ndc - %message%newline" />
|
|
||||||
</layout>
|
|
||||||
</appender>
|
|
||||||
|
|
||||||
<!-- Set root logger level to DEBUG and its only appender to A1 -->
|
|
||||||
<root>
|
|
||||||
<level value="DEBUG" />
|
|
||||||
<appender-ref ref="A1" />
|
|
||||||
</root>
|
|
||||||
</log4net>
|
|
||||||
</configuration>
|
|
|
@ -341,26 +341,13 @@
|
||||||
|
|
||||||
|
|
||||||
[ClientStack.LindenUDP]
|
[ClientStack.LindenUDP]
|
||||||
; This is the multiplier applied to all client throttles for outgoing UDP network data
|
; Set this to true to process incoming packets asynchronously. Networking is
|
||||||
; If it is set to 1, then we obey the throttle settings as given to us by the client. If it is set to 3, for example, then we
|
; already separated from packet handling with a queue, so this will only
|
||||||
; multiply that setting by 3 (e.g. if the client gives us a setting of 250 kilobits per second then we
|
; affect whether networking internals such as packet decoding and
|
||||||
; will actually push down data at a maximum rate of 750 kilobits per second).
|
; acknowledgement accounting are done synchronously or asynchronously
|
||||||
;
|
async_packet_handling = false
|
||||||
; In principle, setting a multiplier greater than 1 will allow data to be pushed down to a client much faster
|
|
||||||
; than its UI allows the setting to go. This may be okay in some situations, such as standalone OpenSim
|
|
||||||
; applications on a LAN. However, the greater the multipler, the higher the risk of packet drop, resulting
|
|
||||||
; in symptoms such as missing terrain or objects. A much better solution is to change the client UI to allow
|
|
||||||
; higher network bandwidth settings directly, though this isn't always possible.
|
|
||||||
;
|
|
||||||
; Currently this setting is 2 by default because we currently send much more texture data than is strictly
|
|
||||||
; necessary. A setting of 1 could result in slow texture transfer. This will be fixed when the transfer
|
|
||||||
; of textures at different levels of quality is improved.
|
|
||||||
;
|
|
||||||
; Pre r7113, this setting was not exposed but was effectively 8. You may want to try this if you encounter
|
|
||||||
; unexpected difficulties
|
|
||||||
client_throttle_multiplier = 2;
|
|
||||||
|
|
||||||
; the client socket receive buffer size determines how many
|
; The client socket receive buffer size determines how many
|
||||||
; incoming requests we can process; the default on .NET is 8192
|
; incoming requests we can process; the default on .NET is 8192
|
||||||
; which is about 2 4k-sized UDP datagrams. On mono this is
|
; which is about 2 4k-sized UDP datagrams. On mono this is
|
||||||
; whatever the underlying operating system has as default; for
|
; whatever the underlying operating system has as default; for
|
||||||
|
@ -374,12 +361,42 @@
|
||||||
; by the system's settings for the maximum client receive buffer
|
; by the system's settings for the maximum client receive buffer
|
||||||
; size (on linux systems you can set that with "sysctl -w
|
; size (on linux systems you can set that with "sysctl -w
|
||||||
; net.core.rmem_max=X")
|
; net.core.rmem_max=X")
|
||||||
;
|
|
||||||
;client_socket_rcvbuf_size = 8388608
|
;client_socket_rcvbuf_size = 8388608
|
||||||
|
|
||||||
; Maximum bits per second to send to any single client. This will override the user's viewer preference settings.
|
; Maximum outbound bytes per second for a single scene. This can be used to
|
||||||
|
; throttle total outbound UDP traffic for a simulator. The default value is
|
||||||
|
; 0, meaning no throttling at the scene level. The example given here is
|
||||||
|
; 20 megabits
|
||||||
|
;scene_throttle_max_bps = 2621440
|
||||||
|
|
||||||
; client_throttle_max_bps = 1500000
|
; Maximum bits per second to send to any single client. This will override
|
||||||
|
; the user's viewer preference settings. The default value is 0, meaning no
|
||||||
|
; aggregate throttling on clients (only per-category throttling). The
|
||||||
|
; example given here is 1.5 megabits
|
||||||
|
;client_throttle_max_bps = 196608
|
||||||
|
|
||||||
|
; Per-client bytes per second rates for the various throttle categories.
|
||||||
|
; These are default values that will be overriden by clients
|
||||||
|
;resend_default = 12500
|
||||||
|
;land_default = 500
|
||||||
|
;wind_default = 500
|
||||||
|
;cloud_default = 50
|
||||||
|
;task_default = 500
|
||||||
|
;texture_default = 500
|
||||||
|
;asset_default = 500
|
||||||
|
;state_default = 500
|
||||||
|
|
||||||
|
; Per-client maximum burst rates in bytes per second for the various
|
||||||
|
; throttle categories. These are default values that will be overriden by
|
||||||
|
; clients
|
||||||
|
;resend_limit = 18750
|
||||||
|
;land_limit = 29750
|
||||||
|
;wind_limit = 18750
|
||||||
|
;cloud_limit = 18750
|
||||||
|
;task_limit = 18750
|
||||||
|
;texture_limit = 55750
|
||||||
|
;asset_limit = 27500
|
||||||
|
;state_limit = 37000
|
||||||
|
|
||||||
[Chat]
|
[Chat]
|
||||||
; Controls whether the chat module is enabled. Default is true.
|
; Controls whether the chat module is enabled. Default is true.
|
||||||
|
@ -1382,6 +1399,10 @@
|
||||||
DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll"
|
DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll"
|
||||||
AssetLoaderArgs = "assets/AssetSets.xml"
|
AssetLoaderArgs = "assets/AssetSets.xml"
|
||||||
|
|
||||||
|
; Disable this to prevent the default asset set from being inserted into the
|
||||||
|
; asset store each time the region starts
|
||||||
|
AssetLoaderEnabled = true
|
||||||
|
|
||||||
[GridService]
|
[GridService]
|
||||||
;; default standalone, overridable in StandaloneCommon.ini
|
;; default standalone, overridable in StandaloneCommon.ini
|
||||||
StorageProvider = "OpenSim.Data.Null.dll:NullRegionData"
|
StorageProvider = "OpenSim.Data.Null.dll:NullRegionData"
|
||||||
|
|
|
@ -50,3 +50,10 @@
|
||||||
|
|
||||||
; Warning level for cache directory size
|
; Warning level for cache directory size
|
||||||
;CacheWarnAt = 30000
|
;CacheWarnAt = 30000
|
||||||
|
|
||||||
|
; Perform a deep scan of all assets within all regions, looking for all assets
|
||||||
|
; present or referenced. Mark all assets found that are already present in the
|
||||||
|
; cache, and request all assets that are found that are not already cached (this
|
||||||
|
; will cause those assets to be cached)
|
||||||
|
;
|
||||||
|
; DeepScanBeforePurge = false
|
||||||
|
|
|
@ -135,6 +135,7 @@
|
||||||
<Reference name="System.Xml"/>
|
<Reference name="System.Xml"/>
|
||||||
<Reference name="System.Data"/>
|
<Reference name="System.Data"/>
|
||||||
<Reference name="System.Drawing"/>
|
<Reference name="System.Drawing"/>
|
||||||
|
<Reference name="BclExtras.dll"/>
|
||||||
<Reference name="OpenMetaverseTypes.dll"/>
|
<Reference name="OpenMetaverseTypes.dll"/>
|
||||||
<Reference name="OpenMetaverse.dll"/>
|
<Reference name="OpenMetaverse.dll"/>
|
||||||
<Reference name="OpenMetaverse.StructuredData.dll"/>
|
<Reference name="OpenMetaverse.StructuredData.dll"/>
|
||||||
|
@ -1767,6 +1768,7 @@
|
||||||
<Reference name="OpenSim.Region.Communications.Local"/>
|
<Reference name="OpenSim.Region.Communications.Local"/>
|
||||||
<Reference name="OpenSim.Region.Physics.Manager"/>
|
<Reference name="OpenSim.Region.Physics.Manager"/>
|
||||||
<Reference name="OpenSim.Services.Interfaces"/>
|
<Reference name="OpenSim.Services.Interfaces"/>
|
||||||
|
<Reference name="BclExtras.dll"/>
|
||||||
<Reference name="XMLRPC.dll"/>
|
<Reference name="XMLRPC.dll"/>
|
||||||
<Reference name="Nini.dll" />
|
<Reference name="Nini.dll" />
|
||||||
<Reference name="log4net.dll"/>
|
<Reference name="log4net.dll"/>
|
||||||
|
@ -3495,7 +3497,6 @@
|
||||||
<Reference name="OpenSim.Tests.Common"/>
|
<Reference name="OpenSim.Tests.Common"/>
|
||||||
<Reference name="OpenSim.Framework"/>
|
<Reference name="OpenSim.Framework"/>
|
||||||
<Reference name="OpenSim.Framework.Serialization"/>
|
<Reference name="OpenSim.Framework.Serialization"/>
|
||||||
<Reference name="OpenSim.Framework.Serialization.External"/>
|
|
||||||
<Reference name="log4net.dll"/>
|
<Reference name="log4net.dll"/>
|
||||||
<Reference name="nunit.framework.dll" />
|
<Reference name="nunit.framework.dll" />
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue