aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/ClientManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/ClientManager.cs')
-rw-r--r--OpenSim/Framework/ClientManager.cs258
1 files changed, 124 insertions, 134 deletions
diff --git a/OpenSim/Framework/ClientManager.cs b/OpenSim/Framework/ClientManager.cs
index 094a3ff..367bc6a 100644
--- a/OpenSim/Framework/ClientManager.cs
+++ b/OpenSim/Framework/ClientManager.cs
@@ -28,193 +28,183 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Reflection; 30using System.Reflection;
31using log4net; 31using System.Net;
32using BclExtras.Collections;
32using OpenMetaverse; 33using OpenMetaverse;
33using OpenMetaverse.Packets; 34using OpenMetaverse.Packets;
34 35
35namespace OpenSim.Framework 36namespace OpenSim.Framework
36{ 37{
37 public delegate void ForEachClientDelegate(IClientAPI client); 38 /// <summary>
38 39 /// Maps from client AgentID and RemoteEndPoint values to IClientAPI
40 /// references for all of the connected clients
41 /// </summary>
39 public class ClientManager 42 public class ClientManager
40 { 43 {
41 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 #region IComparers
42
43 private Dictionary<uint, IClientAPI> m_clients;
44 45
45 public ClientManager() 46 private sealed class UUIDComparer : IComparer<UUID>
46 { 47 {
47 m_clients = new Dictionary<uint, IClientAPI>(); 48 public int Compare(UUID x, UUID y)
48 }
49
50 public void ForEachClient(ForEachClientDelegate whatToDo)
51 {
52 IClientAPI[] LocalClients;
53 lock (m_clients)
54 {
55 LocalClients = new IClientAPI[m_clients.Count];
56 m_clients.Values.CopyTo(LocalClients, 0);
57 }
58
59 for (int i = 0; i < LocalClients.Length; i++)
60 { 49 {
61 try 50 return x.CompareTo(y);
62 {
63 whatToDo(LocalClients[i]);
64 }
65 catch (Exception e)
66 {
67 m_log.Warn("[CLIENT]: Unable to do ForEachClient for one of the clients" + "\n Reason: " + e.ToString());
68 }
69 } 51 }
70 } 52 }
71 53
72 public void Remove(uint id) 54 private sealed class IPEndPointComparer : IComparer<IPEndPoint>
73 { 55 {
74 lock (m_clients) 56 public int Compare(IPEndPoint x, IPEndPoint y)
75 { 57 {
76 m_clients.Remove(id); 58 if (x == null && y == null)
77 } 59 return 0;
78 } 60 else if (x == null)
61 return -1;
62 else if (y == null)
63 return 1;
79 64
80 public void Add(uint id, IClientAPI client) 65 int result = x.Address.Address.CompareTo(y.Address.Address);
81 { 66 if (result == 0) result = x.Port.CompareTo(y.Port);
82 lock (m_clients) 67
83 { 68 return result;
84 m_clients.Add(id, client);
85 } 69 }
86 } 70 }
87 71
72 #endregion IComparers
73
74 /// <summary>An immutable dictionary mapping from <seealso cref="UUID"/>
75 /// to <seealso cref="IClientAPI"/> references</summary>
76 private ImmutableMap<UUID, IClientAPI> m_dict;
77 /// <summary>An immutable dictionary mapping from <seealso cref="IPEndPoint"/>
78 /// to <seealso cref="IClientAPI"/> references</summary>
79 private ImmutableMap<IPEndPoint, IClientAPI> m_dict2;
80 /// <summary>Immutability grants thread safety for concurrent reads and
81 /// read-writes, but not concurrent writes</summary>
82 private object m_writeLock = new object();
83
84 /// <summary>Number of clients in the collection</summary>
85 public int Count { get { return m_dict.Count; } }
86
88 /// <summary> 87 /// <summary>
89 /// Pass incoming packet to client. 88 /// Default constructor
90 /// </summary> 89 /// </summary>
91 /// <param name="circuitCode">uint identifying the connection/client.</param> 90 public ClientManager()
92 /// <param name="packet">object containing the packet.</param>
93 public void InPacket(uint circuitCode, object packet)
94 { 91 {
95 IClientAPI client; 92 m_dict = new ImmutableMap<UUID, IClientAPI>(new UUIDComparer());
96 bool tryGetRet = false; 93 m_dict2 = new ImmutableMap<IPEndPoint, IClientAPI>(new IPEndPointComparer());
97
98 lock (m_clients)
99 tryGetRet = m_clients.TryGetValue(circuitCode, out client);
100
101 if (tryGetRet)
102 {
103 client.InPacket(packet);
104 }
105 } 94 }
106 95
107 public void CloseAllAgents(uint circuitCode) 96 /// <summary>
108 { 97 /// Add a client reference to the collection if it does not already
109 IClientAPI client; 98 /// exist
110 bool tryGetRet = false; 99 /// </summary>
111 lock (m_clients) 100 /// <param name="value">Reference to the client object</param>
112 tryGetRet = m_clients.TryGetValue(circuitCode, out client); 101 /// <returns>True if the client reference was successfully added,
113 if (tryGetRet) 102 /// otherwise false if the given key already existed in the collection</returns>
114 { 103 public bool Add(IClientAPI value)
115 CloseAllCircuits(client.AgentId);
116 }
117 }
118
119 public void CloseAllCircuits(UUID agentId)
120 { 104 {
121 uint[] circuits = GetAllCircuits(agentId); 105 lock (m_writeLock)
122 // We're using a for loop here so changes to the circuits don't cause it to completely fail.
123
124 for (int i = 0; i < circuits.Length; i++)
125 { 106 {
126 IClientAPI client; 107 if (!m_dict.ContainsKey(value.AgentId) && !m_dict2.ContainsKey(value.RemoteEndPoint))
127 try
128 { 108 {
129 bool tryGetRet = false; 109 m_dict = m_dict.Add(value.AgentId, value);
130 lock (m_clients) 110 m_dict2 = m_dict2.Add(value.RemoteEndPoint, value);
131 tryGetRet = m_clients.TryGetValue(circuits[i], out client); 111
132 if (tryGetRet) 112 return true;
133 {
134 Remove(client.CircuitCode);
135 client.Close(false);
136 }
137 } 113 }
138 catch (Exception e) 114 else
139 { 115 {
140 m_log.Error(string.Format("[CLIENT]: Unable to shutdown circuit for: {0}\n Reason: {1}", agentId, e)); 116 return false;
141 } 117 }
142 } 118 }
143 } 119 }
144 120
145 // [Obsolete("Using Obsolete to drive development is invalid. Obsolete presumes that something new has already been created to replace this.")] 121 /// <summary>
146 public uint[] GetAllCircuits(UUID agentId) 122 /// Remove a client from the collection
123 /// </summary>
124 /// <param name="key">UUID of the client to remove</param>
125 /// <returns>True if a client was removed, or false if the given UUID
126 /// was not present in the collection</returns>
127 public bool Remove(UUID key)
147 { 128 {
148 List<uint> circuits = new List<uint>(); 129 lock (m_writeLock)
149 // Wasteful, I know
150 IClientAPI[] LocalClients = new IClientAPI[0];
151 lock (m_clients)
152 { 130 {
153 LocalClients = new IClientAPI[m_clients.Count]; 131 IClientAPI client;
154 m_clients.Values.CopyTo(LocalClients, 0);
155 }
156 132
157 for (int i = 0; i < LocalClients.Length; i++) 133 if (m_dict.TryGetValue(key, out client))
158 {
159 if (LocalClients[i].AgentId == agentId)
160 { 134 {
161 circuits.Add(LocalClients[i].CircuitCode); 135 m_dict = m_dict.Delete(key);
136 m_dict2 = m_dict2.Delete(client.RemoteEndPoint);
137 return true;
138 }
139 else
140 {
141 return false;
162 } 142 }
163 } 143 }
164 return circuits.ToArray();
165 } 144 }
166 145
167 public List<uint> GetAllCircuitCodes() 146 /// <summary>
147 /// Resets the client collection
148 /// </summary>
149 public void Clear()
168 { 150 {
169 List<uint> circuits; 151 lock (m_writeLock)
170
171 lock (m_clients)
172 { 152 {
173 circuits = new List<uint>(m_clients.Keys); 153 m_dict = new ImmutableMap<UUID, IClientAPI>(new UUIDComparer());
154 m_dict2 = new ImmutableMap<IPEndPoint, IClientAPI>(new IPEndPointComparer());
174 } 155 }
156 }
175 157
176 return circuits; 158 /// <summary>
159 /// Checks if a UUID is in the collection
160 /// </summary>
161 /// <param name="key">UUID to check for</param>
162 /// <returns>True if the UUID was found in the collection, otherwise false</returns>
163 public bool ContainsKey(UUID key)
164 {
165 return m_dict.ContainsKey(key);
177 } 166 }
178 167
179 public void ViewerEffectHandler(IClientAPI sender, List<ViewerEffectEventHandlerArg> args) 168 /// <summary>
169 /// Checks if an endpoint is in the collection
170 /// </summary>
171 /// <param name="key">Endpoint to check for</param>
172 /// <returns>True if the endpoint was found in the collection, otherwise false</returns>
173 public bool ContainsKey(IPEndPoint key)
180 { 174 {
181 // TODO: don't create new blocks if recycling an old packet 175 return m_dict2.ContainsKey(key);
182 List<ViewerEffectPacket.EffectBlock> effectBlock = new List<ViewerEffectPacket.EffectBlock>(); 176 }
183 for (int i = 0; i < args.Count; i++)
184 {
185 ViewerEffectPacket.EffectBlock effect = new ViewerEffectPacket.EffectBlock();
186 effect.AgentID = args[i].AgentID;
187 effect.Color = args[i].Color;
188 effect.Duration = args[i].Duration;
189 effect.ID = args[i].ID;
190 effect.Type = args[i].Type;
191 effect.TypeData = args[i].TypeData;
192 effectBlock.Add(effect);
193 }
194 ViewerEffectPacket.EffectBlock[] effectBlockArray = effectBlock.ToArray();
195 177
196 IClientAPI[] LocalClients; 178 /// <summary>
197 lock (m_clients) 179 /// Attempts to fetch a value out of the collection
198 { 180 /// </summary>
199 LocalClients = new IClientAPI[m_clients.Count]; 181 /// <param name="key">UUID of the client to retrieve</param>
200 m_clients.Values.CopyTo(LocalClients, 0); 182 /// <param name="value">Retrieved client, or null on lookup failure</param>
201 } 183 /// <returns>True if the lookup succeeded, otherwise false</returns>
184 public bool TryGetValue(UUID key, out IClientAPI value)
185 {
186 return m_dict.TryGetValue(key, out value);
187 }
202 188
203 for (int i = 0; i < LocalClients.Length; i++) 189 /// <summary>
204 { 190 /// Attempts to fetch a value out of the collection
205 if (LocalClients[i].AgentId != sender.AgentId) 191 /// </summary>
206 { 192 /// <param name="key">Endpoint of the client to retrieve</param>
207 LocalClients[i].SendViewerEffect(effectBlockArray); 193 /// <param name="value">Retrieved client, or null on lookup failure</param>
208 } 194 /// <returns>True if the lookup succeeded, otherwise false</returns>
209 } 195 public bool TryGetValue(IPEndPoint key, out IClientAPI value)
196 {
197 return m_dict2.TryGetValue(key, out value);
210 } 198 }
211 199
212 public bool TryGetClient(uint circuitId, out IClientAPI user) 200 /// <summary>
201 /// Performs a given task in parallel for each of the elements in the
202 /// collection
203 /// </summary>
204 /// <param name="action">Action to perform on each element</param>
205 public void ForEach(Action<IClientAPI> action)
213 { 206 {
214 lock (m_clients) 207 Parallel.ForEach<IClientAPI>(m_dict.Values, action);
215 {
216 return m_clients.TryGetValue(circuitId, out user);
217 }
218 } 208 }
219 } 209 }
220} 210}