* Rewrote ClientManager to remove Lindenisms from OpenSim core, improve performance by removing locks, and replace LLUDPClientCollection
* Removed the confusing (and LL-specific) shutdowncircuit parameter from IClientAPI.Close() * Updated the LLUDP code to only use ClientManager instead of trying to synchronize ClientManager and m_clients * Remove clients asynchronously since it is a very slow operation (including a 2000ms sleep)prioritization
parent
c893761319
commit
23a334b9f5
|
@ -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
|
||||||
|
|
|
@ -341,7 +341,7 @@ namespace OpenSim.Client.MXP.PacketHandler
|
||||||
|
|
||||||
|
|
||||||
m_log.Debug("[MXP ClientStack]: Adding ClientView to Scene...");
|
m_log.Debug("[MXP ClientStack]: Adding ClientView to Scene...");
|
||||||
scene.ClientManager.Add(client.CircuitCode, client);
|
scene.ClientManager.Add(client.AgentId, client.RemoteEndPoint, client);
|
||||||
m_log.Debug("[MXP ClientStack]: Added ClientView to Scene.");
|
m_log.Debug("[MXP ClientStack]: Added ClientView to Scene.");
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -415,7 +415,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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,56 +28,174 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using log4net;
|
using System.Net;
|
||||||
|
using BclExtras.Collections;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenMetaverse.Packets;
|
using OpenMetaverse.Packets;
|
||||||
|
|
||||||
namespace OpenSim.Framework
|
namespace OpenSim.Framework
|
||||||
{
|
{
|
||||||
|
/// <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);
|
#region IComparers
|
||||||
|
|
||||||
private Dictionary<uint, IClientAPI> m_clients = new Dictionary<uint, IClientAPI>();
|
private sealed class UUIDComparer : IComparer<UUID>
|
||||||
|
|
||||||
public void Add(uint circuitCode, IClientAPI client)
|
|
||||||
{
|
{
|
||||||
lock (m_clients)
|
public int Compare(UUID x, UUID y)
|
||||||
m_clients.Add(circuitCode, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(uint circuitCode)
|
|
||||||
{
|
|
||||||
lock (m_clients)
|
|
||||||
return m_clients.Remove(circuitCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetClient(uint circuitCode, out IClientAPI user)
|
|
||||||
{
|
|
||||||
lock (m_clients)
|
|
||||||
return m_clients.TryGetValue(circuitCode, out user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ForEachClient(Action<IClientAPI> action)
|
|
||||||
{
|
|
||||||
IClientAPI[] LocalClients;
|
|
||||||
lock (m_clients)
|
|
||||||
{
|
{
|
||||||
LocalClients = new IClientAPI[m_clients.Count];
|
return x.CompareTo(y);
|
||||||
m_clients.Values.CopyTo(LocalClients, 0);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < LocalClients.Length; i++)
|
private sealed class IPEndPointComparer : IComparer<IPEndPoint>
|
||||||
|
{
|
||||||
|
public int Compare(IPEndPoint x, IPEndPoint y)
|
||||||
{
|
{
|
||||||
try
|
if (x == null && y == null)
|
||||||
|
return 0;
|
||||||
|
else if (x == null)
|
||||||
|
return -1;
|
||||||
|
else if (y == null)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int result = x.Address.Address.CompareTo(y.Address.Address);
|
||||||
|
if (result == 0) result = x.Port.CompareTo(y.Port);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion IComparers
|
||||||
|
|
||||||
|
/// <summary>An immutable dictionary mapping from <seealso cref="UUID"/>
|
||||||
|
/// to <seealso cref="IClientAPI"/> references</summary>
|
||||||
|
private ImmutableMap<UUID, IClientAPI> m_dict;
|
||||||
|
/// <summary>An immutable dictionary mapping from <seealso cref="IPEndPoint"/>
|
||||||
|
/// to <seealso cref="IClientAPI"/> references</summary>
|
||||||
|
private ImmutableMap<IPEndPoint, IClientAPI> m_dict2;
|
||||||
|
/// <summary>Immutability grants thread safety for concurrent reads and
|
||||||
|
/// read-writes, but not concurrent writes</summary>
|
||||||
|
private object m_writeLock = new object();
|
||||||
|
|
||||||
|
/// <summary>Number of clients in the collection</summary>
|
||||||
|
public int Count { get { return m_dict.Count; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default constructor
|
||||||
|
/// </summary>
|
||||||
|
public ClientManager()
|
||||||
|
{
|
||||||
|
m_dict = new ImmutableMap<UUID, IClientAPI>(new UUIDComparer());
|
||||||
|
m_dict2 = new ImmutableMap<IPEndPoint, IClientAPI>(new IPEndPointComparer());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a client reference to the collection if it does not already
|
||||||
|
/// exist
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">UUID of the client</param>
|
||||||
|
/// <param name="key2">Remote endpoint of the client</param>
|
||||||
|
/// <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(UUID key, IPEndPoint key2, IClientAPI value)
|
||||||
|
{
|
||||||
|
lock (m_writeLock)
|
||||||
|
{
|
||||||
|
if (!m_dict.ContainsKey(key) && !m_dict2.ContainsKey(key2))
|
||||||
{
|
{
|
||||||
action(LocalClients[i]);
|
m_dict = m_dict.Add(key, value);
|
||||||
|
m_dict2 = m_dict2.Add(key2, value);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
else
|
||||||
{
|
{
|
||||||
m_log.Warn("[CLIENT]: Unable to do ForEachClient for one of the clients" + "\n Reason: " + e.ToString());
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove a client from the collection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">UUID of the client</param>
|
||||||
|
/// <param name="key2">Remote endpoint of the client</param>
|
||||||
|
public void Remove(UUID key, IPEndPoint key2)
|
||||||
|
{
|
||||||
|
lock (m_writeLock)
|
||||||
|
{
|
||||||
|
m_dict = m_dict.Delete(key);
|
||||||
|
m_dict2 = m_dict2.Delete(key2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the client collection
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
lock (m_writeLock)
|
||||||
|
{
|
||||||
|
m_dict = new ImmutableMap<UUID, IClientAPI>(new UUIDComparer());
|
||||||
|
m_dict2 = new ImmutableMap<IPEndPoint, IClientAPI>(new IPEndPointComparer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a UUID is in the collection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">UUID to check for</param>
|
||||||
|
/// <returns>True if the UUID was found in the collection, otherwise false</returns>
|
||||||
|
public bool ContainsKey(UUID key)
|
||||||
|
{
|
||||||
|
return m_dict.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if an endpoint is in the collection
|
||||||
|
/// </summary>
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return m_dict.TryGetValue(key, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
return m_dict2.TryGetValue(key, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
Parallel.ForEach<IClientAPI>(m_dict.Values, action);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -802,7 +802,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>
|
||||||
|
|
|
@ -403,39 +403,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
#region Client Methods
|
#region Client Methods
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Close down the client view. This *must* be the last method called, since the last #
|
/// Shut down the client view
|
||||||
/// statement of CloseCleanup() aborts the thread.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="shutdownCircuit"></param>
|
public void Close()
|
||||||
public void Close(bool shutdownCircuit)
|
|
||||||
{
|
{
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
"[CLIENT]: Close has been called with shutdownCircuit = {0} for {1} attached to scene {2}",
|
"[CLIENT]: Close has been called for {0} attached to scene {1}",
|
||||||
shutdownCircuit, Name, m_scene.RegionInfo.RegionName);
|
Name, m_scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
// Remove ourselves from the scene
|
||||||
|
m_scene.ClientManager.Remove(m_agentId, m_udpClient.RemoteEndPoint);
|
||||||
|
|
||||||
if (m_imageManager != null)
|
if (m_imageManager != null)
|
||||||
|
{
|
||||||
m_imageManager.Close();
|
m_imageManager.Close();
|
||||||
|
m_imageManager = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_udpServer != null)
|
if (m_udpServer != null)
|
||||||
|
{
|
||||||
m_udpServer.Flush();
|
m_udpServer.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
// raise an event on the packet server to Shutdown the circuit
|
if (OnConnectionClosed != null)
|
||||||
// Now, if we raise the event then the packet server will call this method itself, so don't try cleanup
|
OnConnectionClosed(this);
|
||||||
// here otherwise we'll end up calling it twice.
|
|
||||||
// FIXME: In truth, I might be wrong but this whole business of calling this method twice (with different args) looks
|
CloseCleanup();
|
||||||
// horribly tangly. Hopefully it should be possible to greatly simplify it.
|
|
||||||
if (shutdownCircuit)
|
|
||||||
{
|
|
||||||
if (OnConnectionClosed != null)
|
|
||||||
OnConnectionClosed(this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CloseCleanup(shutdownCircuit);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CloseCleanup(bool shutdownCircuit)
|
private void CloseCleanup()
|
||||||
{
|
{
|
||||||
m_scene.RemoveClient(AgentId);
|
m_scene.RemoveClient(AgentId);
|
||||||
|
|
||||||
|
@ -459,43 +455,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
lock (m_primFullUpdateTimer)
|
lock (m_primFullUpdateTimer)
|
||||||
m_primFullUpdateTimer.Stop();
|
m_primFullUpdateTimer.Stop();
|
||||||
|
|
||||||
// This is just to give the client a reasonable chance of
|
|
||||||
// flushing out all it's packets. There should probably
|
|
||||||
// be a better mechanism here
|
|
||||||
|
|
||||||
// We can't reach into other scenes and close the connection
|
// We can't reach into other scenes and close the connection
|
||||||
// We need to do this over grid communications
|
// We need to do this over grid communications
|
||||||
//m_scene.CloseAllAgents(CircuitCode);
|
//m_scene.CloseAllAgents(CircuitCode);
|
||||||
|
|
||||||
// If we're not shutting down the circuit, then this is the last time we'll go here.
|
|
||||||
// If we are shutting down the circuit, the UDP Server will come back here with
|
|
||||||
// ShutDownCircuit = false
|
|
||||||
if (!(shutdownCircuit))
|
|
||||||
{
|
|
||||||
GC.Collect();
|
|
||||||
m_imageManager = null;
|
|
||||||
// Sends a KillPacket object, with which, the
|
|
||||||
// blockingqueue dequeues and sees it's a killpacket
|
|
||||||
// and terminates within the context of the client thread.
|
|
||||||
// This ensures that it's done from within the context
|
|
||||||
// of the client thread regardless of where Close() is called.
|
|
||||||
KillEndDone();
|
|
||||||
}
|
|
||||||
|
|
||||||
IsActive = false;
|
IsActive = false;
|
||||||
|
|
||||||
m_avatarTerseUpdateTimer.Close();
|
m_avatarTerseUpdateTimer.Dispose();
|
||||||
m_primTerseUpdateTimer.Close();
|
m_primTerseUpdateTimer.Dispose();
|
||||||
m_primFullUpdateTimer.Close();
|
m_primFullUpdateTimer.Dispose();
|
||||||
|
|
||||||
//m_udpServer.OnPacketStats -= PopulateStats;
|
// Disable UDP handling for this client
|
||||||
m_udpClient.Shutdown();
|
m_udpClient.Shutdown();
|
||||||
|
|
||||||
// wait for thread stoped
|
|
||||||
// m_clientThread.Join();
|
|
||||||
|
|
||||||
// delete circuit code
|
|
||||||
//m_networkServer.CloseClient(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Kick(string message)
|
public void Kick(string message)
|
||||||
|
@ -10225,7 +10196,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
public void KillEndDone()
|
public void KillEndDone()
|
||||||
{
|
{
|
||||||
m_udpClient.Shutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IClientCore
|
#region IClientCore
|
||||||
|
@ -10268,15 +10238,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
Kick(reason);
|
Kick(reason);
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
Close(true);
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disconnect()
|
public void Disconnect()
|
||||||
{
|
{
|
||||||
Close(true);
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public void RefreshGroupMembership()
|
public void RefreshGroupMembership()
|
||||||
|
|
|
@ -181,7 +181,6 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,137 +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 BclExtras.Collections;
|
|
||||||
|
|
||||||
using ReaderWriterLockImpl = OpenMetaverse.ReaderWriterLockSlim;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ClientStack.LindenUDP
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A thread safe mapping from endpoints to client references
|
|
||||||
/// </summary>
|
|
||||||
public sealed class UDPClientCollection
|
|
||||||
{
|
|
||||||
#region IComparers
|
|
||||||
|
|
||||||
private sealed class IPEndPointComparer : IComparer<IPEndPoint>
|
|
||||||
{
|
|
||||||
public int Compare(IPEndPoint x, IPEndPoint y)
|
|
||||||
{
|
|
||||||
int result = x.Address.Address.CompareTo(y.Address.Address);
|
|
||||||
if (result == 0) result = x.Port.CompareTo(y.Port);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion IComparers
|
|
||||||
|
|
||||||
/// <summary>An immutable dictionary mapping from <seealso cref="IPEndPoint"/>
|
|
||||||
/// to <seealso cref="LLUDPClient"/> references</summary>
|
|
||||||
private ImmutableMap<IPEndPoint, LLUDPClient> m_dict;
|
|
||||||
/// <summary>Immutability grants thread safety for concurrent reads and
|
|
||||||
/// read-writes, but not concurrent writes</summary>
|
|
||||||
private object m_writeLock = new object();
|
|
||||||
|
|
||||||
/// <summary>Number of clients in the collection</summary>
|
|
||||||
public int Count { get { return m_dict.Count; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Default constructor
|
|
||||||
/// </summary>
|
|
||||||
public UDPClientCollection()
|
|
||||||
{
|
|
||||||
m_dict = new ImmutableMap<IPEndPoint, LLUDPClient>(new IPEndPointComparer());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Add a client reference to the collection
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">Remote endpoint of the client</param>
|
|
||||||
/// <param name="value">Reference to the client object</param>
|
|
||||||
public void Add(IPEndPoint key, LLUDPClient value)
|
|
||||||
{
|
|
||||||
lock (m_writeLock)
|
|
||||||
m_dict = m_dict.Add(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove a client from the collection
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">Remote endpoint of the client</param>
|
|
||||||
public void Remove(IPEndPoint key)
|
|
||||||
{
|
|
||||||
lock (m_writeLock)
|
|
||||||
m_dict = m_dict.Delete(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resets the client collection
|
|
||||||
/// </summary>
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
lock (m_writeLock)
|
|
||||||
m_dict = new ImmutableMap<IPEndPoint, LLUDPClient>(new IPEndPointComparer());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if an endpoint is in the collection
|
|
||||||
/// </summary>
|
|
||||||
/// <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)
|
|
||||||
{
|
|
||||||
return m_dict.ContainsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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 LLUDPClient value)
|
|
||||||
{
|
|
||||||
return m_dict.TryGetValue(key, out value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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<LLUDPClient> action)
|
|
||||||
{
|
|
||||||
Parallel.ForEach<LLUDPClient>(m_dict.Values, 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 m_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>
|
||||||
|
@ -181,23 +181,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
return x == m_location;
|
return x == m_location;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveClient(LLUDPClient udpClient)
|
|
||||||
{
|
|
||||||
m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + udpClient.AgentID);
|
|
||||||
|
|
||||||
// Shut down the IClientAPI and remove it from the scene
|
|
||||||
IClientAPI client;
|
|
||||||
if (m_scene.ClientManager.TryGetClient(udpClient.CircuitCode, out client))
|
|
||||||
{
|
|
||||||
client.Close(false);
|
|
||||||
m_scene.ClientManager.Remove(udpClient.CircuitCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shut down the LLUDPClient and remove it from the list of UDP clients
|
|
||||||
udpClient.Shutdown();
|
|
||||||
m_clients.Remove(udpClient.RemoteEndPoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -215,17 +198,25 @@ 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];
|
||||||
m_clients.ForEach(
|
m_scene.ClientManager.ForEach(
|
||||||
delegate(LLUDPClient client)
|
delegate(IClientAPI client)
|
||||||
{ SendPacketData(client, data, packet.Type, category); });
|
{
|
||||||
|
if (client is LLClientView)
|
||||||
|
SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
byte[] data = packet.ToBytes();
|
byte[] data = packet.ToBytes();
|
||||||
m_clients.ForEach(
|
m_scene.ClientManager.ForEach(
|
||||||
delegate(LLUDPClient client)
|
delegate(IClientAPI client)
|
||||||
{ SendPacketData(client, data, packet.Type, category); });
|
{
|
||||||
|
if (client is LLClientView)
|
||||||
|
SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,7 +466,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
//try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.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;
|
||||||
|
@ -512,30 +503,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine which agent this packet came from
|
// Determine which agent this packet came from
|
||||||
if (!m_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 +
|
m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address +
|
||||||
" in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_clients.Count + " clients");
|
" in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
udpClient = ((LLClientView)client).UDPClient;
|
||||||
|
|
||||||
#endregion Packet to Client Mapping
|
#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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -544,10 +538,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,27 +550,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
#region ACK Sending
|
#region ACK Sending
|
||||||
|
|
||||||
if (packet.Header.Reliable)
|
if (packet.Header.Reliable)
|
||||||
client.PendingAcks.Enqueue(packet.Header.Sequence);
|
udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
|
||||||
|
|
||||||
// This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
|
// This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
|
||||||
// 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);
|
||||||
|
@ -593,7 +587,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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,31 +607,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint)
|
private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint)
|
||||||
{
|
{
|
||||||
|
UUID agentID = useCircuitCode.CircuitCode.ID;
|
||||||
|
UUID sessionID = useCircuitCode.CircuitCode.SessionID;
|
||||||
|
uint circuitCode = useCircuitCode.CircuitCode.Code;
|
||||||
|
|
||||||
if (m_scene.RegionStatus != RegionStatus.SlaveScene)
|
if (m_scene.RegionStatus != RegionStatus.SlaveScene)
|
||||||
{
|
{
|
||||||
if (!m_clients.ContainsKey(remoteEndPoint))
|
AuthenticateResponse sessionInfo;
|
||||||
|
if (IsClientAuthorized(useCircuitCode, out sessionInfo))
|
||||||
{
|
{
|
||||||
AuthenticateResponse sessionInfo;
|
AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo);
|
||||||
if (IsClientAuthorized(useCircuitCode, out sessionInfo))
|
|
||||||
{
|
|
||||||
UUID agentID = useCircuitCode.CircuitCode.ID;
|
|
||||||
UUID sessionID = useCircuitCode.CircuitCode.SessionID;
|
|
||||||
uint circuitCode = useCircuitCode.CircuitCode.Code;
|
|
||||||
|
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
// Ignore repeated UseCircuitCode packets
|
// Don't create circuits for unauthorized clients
|
||||||
m_log.Debug("[LLUDPSERVER]: Ignoring UseCircuitCode for already established circuit " + useCircuitCode.CircuitCode.Code);
|
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
|
else
|
||||||
|
@ -652,17 +638,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
// Create the LLUDPClient
|
// Create the LLUDPClient
|
||||||
LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint);
|
LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint);
|
||||||
|
|
||||||
// Create the LLClientView
|
if (!m_scene.ClientManager.ContainsKey(agentID))
|
||||||
LLClientView clientApi = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
|
{
|
||||||
clientApi.OnLogout += LogoutHandler;
|
// Create the LLClientView
|
||||||
clientApi.OnConnectionClosed += ConnectionClosedHandler;
|
LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
|
||||||
|
client.OnLogout += LogoutHandler;
|
||||||
|
client.OnConnectionClosed += ConnectionClosedHandler;
|
||||||
|
|
||||||
// Start the IClientAPI
|
m_scene.ClientManager.Add(agentID, remoteEndPoint, client);
|
||||||
m_scene.ClientManager.Add(circuitCode, clientApi);
|
|
||||||
clientApi.Start();
|
|
||||||
|
|
||||||
// Add the new client to our list of tracked clients
|
// Start the IClientAPI
|
||||||
m_clients.Add(udpClient.RemoteEndPoint, udpClient);
|
m_scene.ClientManager.Add(agentID, remoteEndPoint, client);
|
||||||
|
client.Start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.Debug("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from " + udpClient.AgentID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveClient(LLUDPClient udpClient)
|
||||||
|
{
|
||||||
|
// Remove this client from the scene ClientManager
|
||||||
|
IClientAPI client;
|
||||||
|
if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client))
|
||||||
|
Util.FireAndForget(delegate(object o) { client.Close(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend)
|
private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend)
|
||||||
|
@ -740,20 +740,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
elapsed500MS = 0;
|
elapsed500MS = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_clients.ForEach(
|
m_scene.ClientManager.ForEach(
|
||||||
delegate(LLUDPClient client)
|
delegate(IClientAPI client)
|
||||||
{
|
{
|
||||||
if (client.DequeueOutgoing())
|
if (client is LLClientView)
|
||||||
packetSent = true;
|
|
||||||
if (resendUnacked)
|
|
||||||
ResendUnacked(client);
|
|
||||||
if (sendAcks)
|
|
||||||
{
|
{
|
||||||
SendAcks(client);
|
LLUDPClient udpClient = ((LLClientView)client).UDPClient;
|
||||||
client.SendPacketStats();
|
|
||||||
|
if (udpClient.DequeueOutgoing())
|
||||||
|
packetSent = true;
|
||||||
|
if (resendUnacked)
|
||||||
|
ResendUnacked(udpClient);
|
||||||
|
if (sendAcks)
|
||||||
|
{
|
||||||
|
SendAcks(udpClient);
|
||||||
|
udpClient.SendPacketStats();
|
||||||
|
}
|
||||||
|
if (sendPings)
|
||||||
|
SendPing(udpClient);
|
||||||
}
|
}
|
||||||
if (sendPings)
|
|
||||||
SendPing(client);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -777,7 +782,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure this client is still alive
|
// Make sure this client is still alive
|
||||||
if (m_scene.ClientManager.TryGetClient(udpClient.CircuitCode, out client))
|
if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -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,15 +112,17 @@ 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);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// This is a bit crude. It seems the client will be null before it actually stops the thread
|
// This is a bit crude. It seems the client will be null before it actually stops the thread
|
||||||
// The thread will kill itself eventually :/
|
// The thread will kill itself eventually :/
|
||||||
// Is there another way to make sure *all* clients get this 'inter region' message?
|
// Is there another way to make sure *all* clients get this 'inter region' message?
|
||||||
m_scene.ForEachScenePresence(
|
m_scene.ForEachScenePresence(
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -813,7 +813,7 @@ namespace OpenSim.Region.Examples.SimpleModule
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close(bool ShutdownCircuit)
|
public void Close()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -408,7 +408,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
ViewerEffectPacket.EffectBlock[] effectBlockArray = effectBlock.ToArray();
|
ViewerEffectPacket.EffectBlock[] effectBlockArray = effectBlock.ToArray();
|
||||||
|
|
||||||
ClientManager.ForEachClient(
|
ClientManager.ForEach(
|
||||||
delegate(IClientAPI client)
|
delegate(IClientAPI client)
|
||||||
{
|
{
|
||||||
if (client.AgentId != remoteClient.AgentId)
|
if (client.AgentId != remoteClient.AgentId)
|
||||||
|
|
|
@ -867,7 +867,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();
|
||||||
|
@ -3372,7 +3372,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
|
||||||
{
|
{
|
||||||
|
@ -3543,7 +3543,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
presence.ControllingClient.SendShutdownConnectionNotice();
|
presence.ControllingClient.SendShutdownConnectionNotice();
|
||||||
}
|
}
|
||||||
|
|
||||||
presence.ControllingClient.Close(true);
|
presence.ControllingClient.Close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ 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);
|
m_scene.ClientManager.Add(cv.AgentId, cv.RemoteEndPoint, 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,8 +183,9 @@ 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(
|
||||||
{ controller.SendKillObject(m_Entity.RegionHandle, part.LocalId); }
|
delegate(IClientAPI controller)
|
||||||
|
{ controller.SendKillObject(m_Entity.RegionHandle, part.LocalId); }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,8 +202,9 @@ namespace OpenSim.Region.OptionalModules.ContentManagement
|
||||||
|
|
||||||
public void SendFullUpdateToAll()
|
public void SendFullUpdateToAll()
|
||||||
{
|
{
|
||||||
m_Entity.Scene.ClientManager.ForEachClient(delegate(IClientAPI controller)
|
m_Entity.Scene.ClientManager.ForEach(
|
||||||
{ m_Entity.SendFullUpdateToClient(controller); }
|
delegate(IClientAPI 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,7 @@ 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.ClientManager.Add(npcAvatar.AgentId, npcAvatar.RemoteEndPoint, npcAvatar);
|
||||||
p_scene.AddNewClient(npcAvatar);
|
p_scene.AddNewClient(npcAvatar);
|
||||||
|
|
||||||
ScenePresence sp;
|
ScenePresence sp;
|
||||||
|
|
|
@ -865,7 +865,7 @@ namespace OpenSim.Tests.Common.Mock
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close(bool ShutdownCircuit)
|
public void Close()
|
||||||
{
|
{
|
||||||
m_scene.RemoveClient(AgentId);
|
m_scene.RemoveClient(AgentId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"/>
|
||||||
|
|
Loading…
Reference in New Issue