aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework')
-rw-r--r--OpenSim/Framework/ClientManager.cs258
-rw-r--r--OpenSim/Framework/Communications/GenericAsyncResult.cs1
-rw-r--r--OpenSim/Framework/Communications/RestClient.cs6
-rw-r--r--OpenSim/Framework/IClientAPI.cs4
-rw-r--r--OpenSim/Framework/IScene.cs1
-rw-r--r--OpenSim/Framework/LocklessQueue.cs130
-rw-r--r--OpenSim/Framework/Parallel.cs3
-rw-r--r--OpenSim/Framework/ThrottleOutPacketType.cs18
8 files changed, 278 insertions, 143 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}
diff --git a/OpenSim/Framework/Communications/GenericAsyncResult.cs b/OpenSim/Framework/Communications/GenericAsyncResult.cs
index efd2f43..8e3f62b 100644
--- a/OpenSim/Framework/Communications/GenericAsyncResult.cs
+++ b/OpenSim/Framework/Communications/GenericAsyncResult.cs
@@ -146,6 +146,7 @@ namespace OpenSim.Framework.Communications
146 // If the operation isn't done, wait for it 146 // If the operation isn't done, wait for it
147 AsyncWaitHandle.WaitOne(); 147 AsyncWaitHandle.WaitOne();
148 AsyncWaitHandle.Close(); 148 AsyncWaitHandle.Close();
149 m_waitHandle.Close();
149 m_waitHandle = null; // Allow early GC 150 m_waitHandle = null; // Allow early GC
150 } 151 }
151 152
diff --git a/OpenSim/Framework/Communications/RestClient.cs b/OpenSim/Framework/Communications/RestClient.cs
index d98f47d..a74169e 100644
--- a/OpenSim/Framework/Communications/RestClient.cs
+++ b/OpenSim/Framework/Communications/RestClient.cs
@@ -105,7 +105,7 @@ namespace OpenSim.Framework.Communications
105 /// <summary> 105 /// <summary>
106 /// This flag will help block the main synchroneous method, in case we run in synchroneous mode 106 /// This flag will help block the main synchroneous method, in case we run in synchroneous mode
107 /// </summary> 107 /// </summary>
108 public static ManualResetEvent _allDone = new ManualResetEvent(false); 108 //public static ManualResetEvent _allDone = new ManualResetEvent(false);
109 109
110 /// <summary> 110 /// <summary>
111 /// Default time out period 111 /// Default time out period
@@ -282,12 +282,12 @@ namespace OpenSim.Framework.Communications
282 else 282 else
283 { 283 {
284 s.Close(); 284 s.Close();
285 _allDone.Set(); 285 //_allDone.Set();
286 } 286 }
287 } 287 }
288 catch (Exception e) 288 catch (Exception e)
289 { 289 {
290 _allDone.Set(); 290 //_allDone.Set();
291 _asyncException = e; 291 _asyncException = e;
292 } 292 }
293 } 293 }
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index d3bd9e7..29846f5 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -561,6 +561,8 @@ namespace OpenSim.Framework
561 // [Obsolete("LLClientView Specific - Circuits are unique to LLClientView")] 561 // [Obsolete("LLClientView Specific - Circuits are unique to LLClientView")]
562 uint CircuitCode { get; } 562 uint CircuitCode { get; }
563 563
564 IPEndPoint RemoteEndPoint { get; }
565
564 event GenericMessage OnGenericMessage; 566 event GenericMessage OnGenericMessage;
565 567
566 // [Obsolete("LLClientView Specific - Replace with more bare-bones arguments.")] 568 // [Obsolete("LLClientView Specific - Replace with more bare-bones arguments.")]
@@ -802,7 +804,7 @@ namespace OpenSim.Framework
802 804
803 void InPacket(object NewPack); 805 void InPacket(object NewPack);
804 void ProcessInPacket(Packet NewPack); 806 void ProcessInPacket(Packet NewPack);
805 void Close(bool ShutdownCircuit); 807 void Close();
806 void Kick(string message); 808 void Kick(string message);
807 809
808 /// <summary> 810 /// <summary>
diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs
index 489653f..f34027d 100644
--- a/OpenSim/Framework/IScene.cs
+++ b/OpenSim/Framework/IScene.cs
@@ -71,7 +71,6 @@ namespace OpenSim.Framework
71 71
72 void AddNewClient(IClientAPI client); 72 void AddNewClient(IClientAPI client);
73 void RemoveClient(UUID agentID); 73 void RemoveClient(UUID agentID);
74 void CloseAllAgents(uint circuitcode);
75 74
76 void Restart(int seconds); 75 void Restart(int seconds);
77 //RegionInfo OtherRegionUp(RegionInfo thisRegion); 76 //RegionInfo OtherRegionUp(RegionInfo thisRegion);
diff --git a/OpenSim/Framework/LocklessQueue.cs b/OpenSim/Framework/LocklessQueue.cs
new file mode 100644
index 0000000..dd3d201
--- /dev/null
+++ b/OpenSim/Framework/LocklessQueue.cs
@@ -0,0 +1,130 @@
1/*
2 * Copyright (c) 2009, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27using System;
28using System.Threading;
29
30namespace OpenSim.Framework
31{
32 public sealed class LocklessQueue<T>
33 {
34 private sealed class SingleLinkNode
35 {
36 public SingleLinkNode Next;
37 public T Item;
38 }
39
40 SingleLinkNode head;
41 SingleLinkNode tail;
42 int count;
43
44 public int Count { get { return count; } }
45
46 public LocklessQueue()
47 {
48 Init();
49 }
50
51 public void Enqueue(T item)
52 {
53 SingleLinkNode oldTail = null;
54 SingleLinkNode oldTailNext;
55
56 SingleLinkNode newNode = new SingleLinkNode();
57 newNode.Item = item;
58
59 bool newNodeWasAdded = false;
60
61 while (!newNodeWasAdded)
62 {
63 oldTail = tail;
64 oldTailNext = oldTail.Next;
65
66 if (tail == oldTail)
67 {
68 if (oldTailNext == null)
69 newNodeWasAdded = CAS(ref tail.Next, null, newNode);
70 else
71 CAS(ref tail, oldTail, oldTailNext);
72 }
73 }
74
75 CAS(ref tail, oldTail, newNode);
76 Interlocked.Increment(ref count);
77 }
78
79 public bool Dequeue(out T item)
80 {
81 item = default(T);
82 SingleLinkNode oldHead = null;
83 bool haveAdvancedHead = false;
84
85 while (!haveAdvancedHead)
86 {
87 oldHead = head;
88 SingleLinkNode oldTail = tail;
89 SingleLinkNode oldHeadNext = oldHead.Next;
90
91 if (oldHead == head)
92 {
93 if (oldHead == oldTail)
94 {
95 if (oldHeadNext == null)
96 return false;
97
98 CAS(ref tail, oldTail, oldHeadNext);
99 }
100 else
101 {
102 item = oldHeadNext.Item;
103 haveAdvancedHead = CAS(ref head, oldHead, oldHeadNext);
104 }
105 }
106 }
107
108 Interlocked.Decrement(ref count);
109 return true;
110 }
111
112 public void Clear()
113 {
114 Init();
115 }
116
117 private void Init()
118 {
119 count = 0;
120 head = tail = new SingleLinkNode();
121 }
122
123 private static bool CAS(ref SingleLinkNode location, SingleLinkNode comparand, SingleLinkNode newValue)
124 {
125 return
126 (object)comparand ==
127 (object)Interlocked.CompareExchange<SingleLinkNode>(ref location, newValue, comparand);
128 }
129 }
130} \ No newline at end of file
diff --git a/OpenSim/Framework/Parallel.cs b/OpenSim/Framework/Parallel.cs
index 74537ba..6efdad0 100644
--- a/OpenSim/Framework/Parallel.cs
+++ b/OpenSim/Framework/Parallel.cs
@@ -89,6 +89,7 @@ namespace OpenSim.Framework
89 } 89 }
90 90
91 threadFinishEvent.WaitOne(); 91 threadFinishEvent.WaitOne();
92 threadFinishEvent.Close();
92 93
93 if (exception != null) 94 if (exception != null)
94 throw new Exception(exception.Message, exception); 95 throw new Exception(exception.Message, exception);
@@ -148,6 +149,7 @@ namespace OpenSim.Framework
148 } 149 }
149 150
150 threadFinishEvent.WaitOne(); 151 threadFinishEvent.WaitOne();
152 threadFinishEvent.Close();
151 153
152 if (exception != null) 154 if (exception != null)
153 throw new Exception(exception.Message, exception); 155 throw new Exception(exception.Message, exception);
@@ -199,6 +201,7 @@ namespace OpenSim.Framework
199 } 201 }
200 202
201 threadFinishEvent.WaitOne(); 203 threadFinishEvent.WaitOne();
204 threadFinishEvent.Close();
202 205
203 if (exception != null) 206 if (exception != null)
204 throw new Exception(exception.Message, exception); 207 throw new Exception(exception.Message, exception);
diff --git a/OpenSim/Framework/ThrottleOutPacketType.cs b/OpenSim/Framework/ThrottleOutPacketType.cs
index fd490a5..eb42fea 100644
--- a/OpenSim/Framework/ThrottleOutPacketType.cs
+++ b/OpenSim/Framework/ThrottleOutPacketType.cs
@@ -31,13 +31,23 @@ namespace OpenSim.Framework
31{ 31{
32 public enum ThrottleOutPacketType : int 32 public enum ThrottleOutPacketType : int
33 { 33 {
34 Unknown = -1, // Also doubles as 'do not throttle' 34 /// <summary>Unthrottled packets</summary>
35 Unknown = -1,
36 /// <summary>Packets that are being resent</summary>
35 Resend = 0, 37 Resend = 0,
38 /// <summary>Terrain data</summary>
36 Land = 1, 39 Land = 1,
40 /// <summary>Wind data</summary>
37 Wind = 2, 41 Wind = 2,
42 /// <summary>Cloud data</summary>
38 Cloud = 3, 43 Cloud = 3,
39 Task = 4, 44 /// <summary>Texture assets</summary>
40 Texture = 5, 45 Texture = 4,
41 Asset = 6, 46 /// <summary>Non-texture assets</summary>
47 Asset = 5,
48 /// <summary>Avatar and primitive data</summary>
49 State = 6,
50 /// <summary>Any packets that do not fit into the other throttles</summary>
51 Task = 7,
42 } 52 }
43} 53}