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