diff options
Diffstat (limited to '')
40 files changed, 1345 insertions, 1679 deletions
diff --git a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs index bc1b2e5..bc02bc4 100644 --- a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs +++ b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs | |||
@@ -774,6 +774,11 @@ namespace OpenSim.Client.MXP.ClientStack | |||
774 | get { return m_sessionID.CRC(); } | 774 | get { return m_sessionID.CRC(); } |
775 | } | 775 | } |
776 | 776 | ||
777 | public IPEndPoint RemoteEndPoint | ||
778 | { | ||
779 | get { return Session.RemoteEndPoint; } | ||
780 | } | ||
781 | |||
777 | public void SetDebugPacketLevel(int newDebug) | 782 | public void SetDebugPacketLevel(int newDebug) |
778 | { | 783 | { |
779 | //m_debugLevel = newDebug; | 784 | //m_debugLevel = newDebug; |
@@ -798,9 +803,9 @@ namespace OpenSim.Client.MXP.ClientStack | |||
798 | OnConnectionClosed(this); | 803 | OnConnectionClosed(this); |
799 | } | 804 | } |
800 | 805 | ||
801 | public void Close(bool ShutdownCircuit) | 806 | public void Close() |
802 | { | 807 | { |
803 | m_log.Info("[MXP ClientStack] Close Called with SC=" + ShutdownCircuit); | 808 | m_log.Info("[MXP ClientStack] Close Called"); |
804 | 809 | ||
805 | // Tell the client to go | 810 | // Tell the client to go |
806 | SendLogoutPacket(); | 811 | SendLogoutPacket(); |
@@ -815,7 +820,7 @@ namespace OpenSim.Client.MXP.ClientStack | |||
815 | 820 | ||
816 | public void Kick(string message) | 821 | public void Kick(string message) |
817 | { | 822 | { |
818 | Close(false); | 823 | Close(); |
819 | } | 824 | } |
820 | 825 | ||
821 | public void Start() | 826 | public void Start() |
@@ -1448,7 +1453,7 @@ namespace OpenSim.Client.MXP.ClientStack | |||
1448 | 1453 | ||
1449 | public void Terminate() | 1454 | public void Terminate() |
1450 | { | 1455 | { |
1451 | Close(false); | 1456 | Close(); |
1452 | } | 1457 | } |
1453 | 1458 | ||
1454 | public void SendSetFollowCamProperties(UUID objectID, SortedDictionary<int, float> parameters) | 1459 | public void SendSetFollowCamProperties(UUID objectID, SortedDictionary<int, float> parameters) |
@@ -1615,12 +1620,12 @@ namespace OpenSim.Client.MXP.ClientStack | |||
1615 | public void Disconnect(string reason) | 1620 | public void Disconnect(string reason) |
1616 | { | 1621 | { |
1617 | Kick(reason); | 1622 | Kick(reason); |
1618 | Close(true); | 1623 | Close(); |
1619 | } | 1624 | } |
1620 | 1625 | ||
1621 | public void Disconnect() | 1626 | public void Disconnect() |
1622 | { | 1627 | { |
1623 | Close(true); | 1628 | Close(); |
1624 | } | 1629 | } |
1625 | 1630 | ||
1626 | #endregion | 1631 | #endregion |
diff --git a/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs b/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs index 4910ab1..ba9c653 100644 --- a/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs +++ b/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs | |||
@@ -339,12 +339,6 @@ namespace OpenSim.Client.MXP.PacketHandler | |||
339 | m_clients.Add(client); | 339 | m_clients.Add(client); |
340 | m_log.Debug("[MXP ClientStack]: Created ClientView."); | 340 | m_log.Debug("[MXP ClientStack]: Created ClientView."); |
341 | 341 | ||
342 | |||
343 | m_log.Debug("[MXP ClientStack]: Adding ClientView to Scene..."); | ||
344 | scene.ClientManager.Add(client.CircuitCode, client); | ||
345 | m_log.Debug("[MXP ClientStack]: Added ClientView to Scene."); | ||
346 | |||
347 | |||
348 | client.MXPSendSynchronizationBegin(m_scenes[new UUID(joinRequestMessage.BubbleId)].SceneContents.GetTotalObjectsCount()); | 342 | client.MXPSendSynchronizationBegin(m_scenes[new UUID(joinRequestMessage.BubbleId)].SceneContents.GetTotalObjectsCount()); |
349 | 343 | ||
350 | m_log.Debug("[MXP ClientStack]: Starting ClientView..."); | 344 | m_log.Debug("[MXP ClientStack]: Starting ClientView..."); |
diff --git a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs index c649c5a..e3abcf5 100644 --- a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs +++ b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs | |||
@@ -207,6 +207,11 @@ namespace OpenSim.Client.VWoHTTP.ClientStack | |||
207 | get { throw new System.NotImplementedException(); } | 207 | get { throw new System.NotImplementedException(); } |
208 | } | 208 | } |
209 | 209 | ||
210 | public IPEndPoint RemoteEndPoint | ||
211 | { | ||
212 | get { throw new System.NotImplementedException(); } | ||
213 | } | ||
214 | |||
210 | public event GenericMessage OnGenericMessage = delegate { }; | 215 | public event GenericMessage OnGenericMessage = delegate { }; |
211 | public event ImprovedInstantMessage OnInstantMessage = delegate { }; | 216 | public event ImprovedInstantMessage OnInstantMessage = delegate { }; |
212 | public event ChatMessage OnChatFromClient = delegate { }; | 217 | public event ChatMessage OnChatFromClient = delegate { }; |
@@ -415,7 +420,7 @@ namespace OpenSim.Client.VWoHTTP.ClientStack | |||
415 | throw new System.NotImplementedException(); | 420 | throw new System.NotImplementedException(); |
416 | } | 421 | } |
417 | 422 | ||
418 | public void Close(bool ShutdownCircuit) | 423 | public void Close() |
419 | { | 424 | { |
420 | throw new System.NotImplementedException(); | 425 | throw new System.NotImplementedException(); |
421 | } | 426 | } |
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 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using log4net; | 31 | using System.Net; |
32 | using OpenMetaverse; | 32 | using OpenMetaverse; |
33 | using OpenMetaverse.Packets; | 33 | using OpenMetaverse.Packets; |
34 | 34 | ||
35 | namespace OpenSim.Framework | 35 | namespace 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 | } |
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 | |||
27 | using System; | ||
28 | using System.Threading; | ||
29 | |||
30 | namespace 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..e21ff32 100644 --- a/OpenSim/Framework/ThrottleOutPacketType.cs +++ b/OpenSim/Framework/ThrottleOutPacketType.cs | |||
@@ -31,13 +31,24 @@ 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, |
44 | /// <summary>Any packets that do not fit into the other throttles</summary> | ||
39 | Task = 4, | 45 | Task = 4, |
46 | /// <summary>Texture assets</summary> | ||
40 | Texture = 5, | 47 | Texture = 5, |
48 | /// <summary>Non-texture assets</summary> | ||
41 | Asset = 6, | 49 | Asset = 6, |
50 | /// <summary>Avatar and primitive data</summary> | ||
51 | /// <remarks>This is a sub-category of Task</remarks> | ||
52 | State = 7, | ||
42 | } | 53 | } |
43 | } | 54 | } |
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 4d8409bb..ca6a2a3 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs | |||
@@ -239,6 +239,10 @@ namespace OpenSim | |||
239 | "show users [full]", | 239 | "show users [full]", |
240 | "Show user data", HandleShow); | 240 | "Show user data", HandleShow); |
241 | 241 | ||
242 | m_console.Commands.AddCommand("region", false, "show connections", | ||
243 | "show connections", | ||
244 | "Show connection data", HandleShow); | ||
245 | |||
242 | m_console.Commands.AddCommand("region", false, "show users full", | 246 | m_console.Commands.AddCommand("region", false, "show users full", |
243 | "show users full", | 247 | "show users full", |
244 | String.Empty, HandleShow); | 248 | String.Empty, HandleShow); |
@@ -921,7 +925,25 @@ namespace OpenSim | |||
921 | regionName)); | 925 | regionName)); |
922 | } | 926 | } |
923 | 927 | ||
924 | m_log.Info(""); | 928 | m_log.Info(String.Empty); |
929 | break; | ||
930 | |||
931 | case "connections": | ||
932 | System.Text.StringBuilder connections = new System.Text.StringBuilder("Connections:\n"); | ||
933 | m_sceneManager.ForEachScene( | ||
934 | delegate(Scene scene) | ||
935 | { | ||
936 | scene.ClientManager.ForEachSync( | ||
937 | delegate(IClientAPI client) | ||
938 | { | ||
939 | connections.AppendFormat("{0}: {1} ({2}) from {3} on circuit {4}\n", | ||
940 | scene.RegionInfo.RegionName, client.Name, client.AgentId, client.RemoteEndPoint, client.CircuitCode); | ||
941 | } | ||
942 | ); | ||
943 | } | ||
944 | ); | ||
945 | |||
946 | m_log.Info(connections.ToString()); | ||
925 | break; | 947 | break; |
926 | 948 | ||
927 | case "modules": | 949 | case "modules": |
diff --git a/OpenSim/Region/Application/OpenSimBackground.cs b/OpenSim/Region/Application/OpenSimBackground.cs index ac5e241..008c6b0 100644 --- a/OpenSim/Region/Application/OpenSimBackground.cs +++ b/OpenSim/Region/Application/OpenSimBackground.cs | |||
@@ -58,6 +58,7 @@ namespace OpenSim | |||
58 | m_clientServers.Count.ToString(), m_clientServers.Count > 1 ? "s" : ""); | 58 | m_clientServers.Count.ToString(), m_clientServers.Count > 1 ? "s" : ""); |
59 | 59 | ||
60 | WorldHasComeToAnEnd.WaitOne(); | 60 | WorldHasComeToAnEnd.WaitOne(); |
61 | WorldHasComeToAnEnd.Close(); | ||
61 | } | 62 | } |
62 | 63 | ||
63 | /// <summary> | 64 | /// <summary> |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs index bb98f24..b53a2fb 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs | |||
@@ -75,14 +75,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
75 | m_imageManager = imageManager; | 75 | m_imageManager = imageManager; |
76 | } | 76 | } |
77 | 77 | ||
78 | public bool SendPackets(LLClientView client, int maxpack) | 78 | /// <summary> |
79 | /// Sends packets for this texture to a client until packetsToSend is | ||
80 | /// hit or the transfer completes | ||
81 | /// </summary> | ||
82 | /// <param name="client">Reference to the client that the packets are destined for</param> | ||
83 | /// <param name="packetsToSend">Maximum number of packets to send during this call</param> | ||
84 | /// <param name="packetsSent">Number of packets sent during this call</param> | ||
85 | /// <returns>True if the transfer completes at the current discard level, otherwise false</returns> | ||
86 | public bool SendPackets(LLClientView client, int packetsToSend, out int packetsSent) | ||
79 | { | 87 | { |
80 | if (client == null) | 88 | packetsSent = 0; |
81 | return false; | ||
82 | 89 | ||
83 | if (m_currentPacket <= m_stopPacket) | 90 | if (m_currentPacket <= m_stopPacket) |
84 | { | 91 | { |
85 | int count = 0; | ||
86 | bool sendMore = true; | 92 | bool sendMore = true; |
87 | 93 | ||
88 | if (!m_sentInfo || (m_currentPacket == 0)) | 94 | if (!m_sentInfo || (m_currentPacket == 0)) |
@@ -91,25 +97,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
91 | 97 | ||
92 | m_sentInfo = true; | 98 | m_sentInfo = true; |
93 | ++m_currentPacket; | 99 | ++m_currentPacket; |
94 | ++count; | 100 | ++packetsSent; |
95 | } | 101 | } |
96 | if (m_currentPacket < 2) | 102 | if (m_currentPacket < 2) |
97 | { | 103 | { |
98 | m_currentPacket = 2; | 104 | m_currentPacket = 2; |
99 | } | 105 | } |
100 | 106 | ||
101 | while (sendMore && count < maxpack && m_currentPacket <= m_stopPacket) | 107 | while (sendMore && packetsSent < packetsToSend && m_currentPacket <= m_stopPacket) |
102 | { | 108 | { |
103 | sendMore = SendPacket(client); | 109 | sendMore = SendPacket(client); |
104 | ++m_currentPacket; | 110 | ++m_currentPacket; |
105 | ++count; | 111 | ++packetsSent; |
106 | } | 112 | } |
107 | |||
108 | if (m_currentPacket > m_stopPacket) | ||
109 | return true; | ||
110 | } | 113 | } |
111 | 114 | ||
112 | return false; | 115 | return (m_currentPacket > m_stopPacket); |
113 | } | 116 | } |
114 | 117 | ||
115 | public void RunUpdate() | 118 | public void RunUpdate() |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index d64f655..8487adc 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | |||
@@ -59,6 +59,209 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
59 | /// </summary> | 59 | /// </summary> |
60 | public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientIPEndpoint, IStatsCollector | 60 | public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientIPEndpoint, IStatsCollector |
61 | { | 61 | { |
62 | #region Events | ||
63 | |||
64 | public event GenericMessage OnGenericMessage; | ||
65 | public event BinaryGenericMessage OnBinaryGenericMessage; | ||
66 | public event Action<IClientAPI> OnLogout; | ||
67 | public event ObjectPermissions OnObjectPermissions; | ||
68 | public event Action<IClientAPI> OnConnectionClosed; | ||
69 | public event ViewerEffectEventHandler OnViewerEffect; | ||
70 | public event ImprovedInstantMessage OnInstantMessage; | ||
71 | public event ChatMessage OnChatFromClient; | ||
72 | public event TextureRequest OnRequestTexture; | ||
73 | public event RezObject OnRezObject; | ||
74 | public event DeRezObject OnDeRezObject; | ||
75 | public event ModifyTerrain OnModifyTerrain; | ||
76 | public event Action<IClientAPI> OnRegionHandShakeReply; | ||
77 | public event GenericCall2 OnRequestWearables; | ||
78 | public event SetAppearance OnSetAppearance; | ||
79 | public event AvatarNowWearing OnAvatarNowWearing; | ||
80 | public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; | ||
81 | public event RezMultipleAttachmentsFromInv OnRezMultipleAttachmentsFromInv; | ||
82 | public event UUIDNameRequest OnDetachAttachmentIntoInv; | ||
83 | public event ObjectAttach OnObjectAttach; | ||
84 | public event ObjectDeselect OnObjectDetach; | ||
85 | public event ObjectDrop OnObjectDrop; | ||
86 | public event GenericCall2 OnCompleteMovementToRegion; | ||
87 | public event UpdateAgent OnAgentUpdate; | ||
88 | public event AgentRequestSit OnAgentRequestSit; | ||
89 | public event AgentSit OnAgentSit; | ||
90 | public event AvatarPickerRequest OnAvatarPickerRequest; | ||
91 | public event StartAnim OnStartAnim; | ||
92 | public event StopAnim OnStopAnim; | ||
93 | public event Action<IClientAPI> OnRequestAvatarsData; | ||
94 | public event LinkObjects OnLinkObjects; | ||
95 | public event DelinkObjects OnDelinkObjects; | ||
96 | public event GrabObject OnGrabObject; | ||
97 | public event DeGrabObject OnDeGrabObject; | ||
98 | public event SpinStart OnSpinStart; | ||
99 | public event SpinStop OnSpinStop; | ||
100 | public event ObjectDuplicate OnObjectDuplicate; | ||
101 | public event ObjectDuplicateOnRay OnObjectDuplicateOnRay; | ||
102 | public event MoveObject OnGrabUpdate; | ||
103 | public event SpinObject OnSpinUpdate; | ||
104 | public event AddNewPrim OnAddPrim; | ||
105 | public event RequestGodlikePowers OnRequestGodlikePowers; | ||
106 | public event GodKickUser OnGodKickUser; | ||
107 | public event ObjectExtraParams OnUpdateExtraParams; | ||
108 | public event UpdateShape OnUpdatePrimShape; | ||
109 | public event ObjectRequest OnObjectRequest; | ||
110 | public event ObjectSelect OnObjectSelect; | ||
111 | public event ObjectDeselect OnObjectDeselect; | ||
112 | public event GenericCall7 OnObjectDescription; | ||
113 | public event GenericCall7 OnObjectName; | ||
114 | public event GenericCall7 OnObjectClickAction; | ||
115 | public event GenericCall7 OnObjectMaterial; | ||
116 | public event ObjectIncludeInSearch OnObjectIncludeInSearch; | ||
117 | public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; | ||
118 | public event UpdatePrimFlags OnUpdatePrimFlags; | ||
119 | public event UpdatePrimTexture OnUpdatePrimTexture; | ||
120 | public event UpdateVector OnUpdatePrimGroupPosition; | ||
121 | public event UpdateVector OnUpdatePrimSinglePosition; | ||
122 | public event UpdatePrimRotation OnUpdatePrimGroupRotation; | ||
123 | public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation; | ||
124 | public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition; | ||
125 | public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation; | ||
126 | public event UpdateVector OnUpdatePrimScale; | ||
127 | public event UpdateVector OnUpdatePrimGroupScale; | ||
128 | public event StatusChange OnChildAgentStatus; | ||
129 | public event GenericCall2 OnStopMovement; | ||
130 | public event Action<UUID> OnRemoveAvatar; | ||
131 | public event RequestMapBlocks OnRequestMapBlocks; | ||
132 | public event RequestMapName OnMapNameRequest; | ||
133 | public event TeleportLocationRequest OnTeleportLocationRequest; | ||
134 | public event TeleportLandmarkRequest OnTeleportLandmarkRequest; | ||
135 | public event DisconnectUser OnDisconnectUser; | ||
136 | public event RequestAvatarProperties OnRequestAvatarProperties; | ||
137 | public event SetAlwaysRun OnSetAlwaysRun; | ||
138 | public event FetchInventory OnAgentDataUpdateRequest; | ||
139 | public event TeleportLocationRequest OnSetStartLocationRequest; | ||
140 | public event UpdateAvatarProperties OnUpdateAvatarProperties; | ||
141 | public event CreateNewInventoryItem OnCreateNewInventoryItem; | ||
142 | public event CreateInventoryFolder OnCreateNewInventoryFolder; | ||
143 | public event UpdateInventoryFolder OnUpdateInventoryFolder; | ||
144 | public event MoveInventoryFolder OnMoveInventoryFolder; | ||
145 | public event FetchInventoryDescendents OnFetchInventoryDescendents; | ||
146 | public event PurgeInventoryDescendents OnPurgeInventoryDescendents; | ||
147 | public event FetchInventory OnFetchInventory; | ||
148 | public event RequestTaskInventory OnRequestTaskInventory; | ||
149 | public event UpdateInventoryItem OnUpdateInventoryItem; | ||
150 | public event CopyInventoryItem OnCopyInventoryItem; | ||
151 | public event MoveInventoryItem OnMoveInventoryItem; | ||
152 | public event RemoveInventoryItem OnRemoveInventoryItem; | ||
153 | public event RemoveInventoryFolder OnRemoveInventoryFolder; | ||
154 | public event UDPAssetUploadRequest OnAssetUploadRequest; | ||
155 | public event XferReceive OnXferReceive; | ||
156 | public event RequestXfer OnRequestXfer; | ||
157 | public event ConfirmXfer OnConfirmXfer; | ||
158 | public event AbortXfer OnAbortXfer; | ||
159 | public event RequestTerrain OnRequestTerrain; | ||
160 | public event RezScript OnRezScript; | ||
161 | public event UpdateTaskInventory OnUpdateTaskInventory; | ||
162 | public event MoveTaskInventory OnMoveTaskItem; | ||
163 | public event RemoveTaskInventory OnRemoveTaskItem; | ||
164 | public event RequestAsset OnRequestAsset; | ||
165 | public event UUIDNameRequest OnNameFromUUIDRequest; | ||
166 | public event ParcelAccessListRequest OnParcelAccessListRequest; | ||
167 | public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest; | ||
168 | public event ParcelPropertiesRequest OnParcelPropertiesRequest; | ||
169 | public event ParcelDivideRequest OnParcelDivideRequest; | ||
170 | public event ParcelJoinRequest OnParcelJoinRequest; | ||
171 | public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest; | ||
172 | public event ParcelSelectObjects OnParcelSelectObjects; | ||
173 | public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest; | ||
174 | public event ParcelAbandonRequest OnParcelAbandonRequest; | ||
175 | public event ParcelGodForceOwner OnParcelGodForceOwner; | ||
176 | public event ParcelReclaim OnParcelReclaim; | ||
177 | public event ParcelReturnObjectsRequest OnParcelReturnObjectsRequest; | ||
178 | public event ParcelDeedToGroup OnParcelDeedToGroup; | ||
179 | public event RegionInfoRequest OnRegionInfoRequest; | ||
180 | public event EstateCovenantRequest OnEstateCovenantRequest; | ||
181 | public event FriendActionDelegate OnApproveFriendRequest; | ||
182 | public event FriendActionDelegate OnDenyFriendRequest; | ||
183 | public event FriendshipTermination OnTerminateFriendship; | ||
184 | public event MoneyTransferRequest OnMoneyTransferRequest; | ||
185 | public event EconomyDataRequest OnEconomyDataRequest; | ||
186 | public event MoneyBalanceRequest OnMoneyBalanceRequest; | ||
187 | public event ParcelBuy OnParcelBuy; | ||
188 | public event UUIDNameRequest OnTeleportHomeRequest; | ||
189 | public event UUIDNameRequest OnUUIDGroupNameRequest; | ||
190 | public event ScriptAnswer OnScriptAnswer; | ||
191 | public event RequestPayPrice OnRequestPayPrice; | ||
192 | public event ObjectSaleInfo OnObjectSaleInfo; | ||
193 | public event ObjectBuy OnObjectBuy; | ||
194 | public event BuyObjectInventory OnBuyObjectInventory; | ||
195 | public event AgentSit OnUndo; | ||
196 | public event ForceReleaseControls OnForceReleaseControls; | ||
197 | public event GodLandStatRequest OnLandStatRequest; | ||
198 | public event RequestObjectPropertiesFamily OnObjectGroupRequest; | ||
199 | public event DetailedEstateDataRequest OnDetailedEstateDataRequest; | ||
200 | public event SetEstateFlagsRequest OnSetEstateFlagsRequest; | ||
201 | public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture; | ||
202 | public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture; | ||
203 | public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights; | ||
204 | public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest; | ||
205 | public event SetRegionTerrainSettings OnSetRegionTerrainSettings; | ||
206 | public event BakeTerrain OnBakeTerrain; | ||
207 | public event RequestTerrain OnUploadTerrain; | ||
208 | public event EstateChangeInfo OnEstateChangeInfo; | ||
209 | public event EstateRestartSimRequest OnEstateRestartSimRequest; | ||
210 | public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest; | ||
211 | public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest; | ||
212 | public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest; | ||
213 | public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest; | ||
214 | public event EstateDebugRegionRequest OnEstateDebugRegionRequest; | ||
215 | public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest; | ||
216 | public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; | ||
217 | public event RegionHandleRequest OnRegionHandleRequest; | ||
218 | public event ParcelInfoRequest OnParcelInfoRequest; | ||
219 | public event ScriptReset OnScriptReset; | ||
220 | public event GetScriptRunning OnGetScriptRunning; | ||
221 | public event SetScriptRunning OnSetScriptRunning; | ||
222 | public event UpdateVector OnAutoPilotGo; | ||
223 | public event TerrainUnacked OnUnackedTerrain; | ||
224 | public event ActivateGesture OnActivateGesture; | ||
225 | public event DeactivateGesture OnDeactivateGesture; | ||
226 | public event ObjectOwner OnObjectOwner; | ||
227 | public event DirPlacesQuery OnDirPlacesQuery; | ||
228 | public event DirFindQuery OnDirFindQuery; | ||
229 | public event DirLandQuery OnDirLandQuery; | ||
230 | public event DirPopularQuery OnDirPopularQuery; | ||
231 | public event DirClassifiedQuery OnDirClassifiedQuery; | ||
232 | public event EventInfoRequest OnEventInfoRequest; | ||
233 | public event ParcelSetOtherCleanTime OnParcelSetOtherCleanTime; | ||
234 | public event MapItemRequest OnMapItemRequest; | ||
235 | public event OfferCallingCard OnOfferCallingCard; | ||
236 | public event AcceptCallingCard OnAcceptCallingCard; | ||
237 | public event DeclineCallingCard OnDeclineCallingCard; | ||
238 | public event SoundTrigger OnSoundTrigger; | ||
239 | public event StartLure OnStartLure; | ||
240 | public event TeleportLureRequest OnTeleportLureRequest; | ||
241 | public event NetworkStats OnNetworkStatsUpdate; | ||
242 | public event ClassifiedInfoRequest OnClassifiedInfoRequest; | ||
243 | public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; | ||
244 | public event ClassifiedDelete OnClassifiedDelete; | ||
245 | public event ClassifiedDelete OnClassifiedGodDelete; | ||
246 | public event EventNotificationAddRequest OnEventNotificationAddRequest; | ||
247 | public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; | ||
248 | public event EventGodDelete OnEventGodDelete; | ||
249 | public event ParcelDwellRequest OnParcelDwellRequest; | ||
250 | public event UserInfoRequest OnUserInfoRequest; | ||
251 | public event UpdateUserInfo OnUpdateUserInfo; | ||
252 | public event RetrieveInstantMessages OnRetrieveInstantMessages; | ||
253 | public event PickDelete OnPickDelete; | ||
254 | public event PickGodDelete OnPickGodDelete; | ||
255 | public event PickInfoUpdate OnPickInfoUpdate; | ||
256 | public event AvatarNotesUpdate OnAvatarNotesUpdate; | ||
257 | public event MuteListRequest OnMuteListRequest; | ||
258 | public event AvatarInterestUpdate OnAvatarInterestUpdate; | ||
259 | public event PlacesQuery OnPlacesQuery; | ||
260 | |||
261 | #endregion Events | ||
262 | |||
263 | #region Class Members | ||
264 | |||
62 | // LLClientView Only | 265 | // LLClientView Only |
63 | public delegate void BinaryGenericMessage(Object sender, string method, byte[][] args); | 266 | public delegate void BinaryGenericMessage(Object sender, string method, byte[][] args); |
64 | 267 | ||
@@ -111,17 +314,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
111 | protected int m_primFullUpdatesPerPacket = 14; | 314 | protected int m_primFullUpdatesPerPacket = 14; |
112 | protected int m_primTerseUpdateRate = 10; | 315 | protected int m_primTerseUpdateRate = 10; |
113 | protected int m_primFullUpdateRate = 14; | 316 | protected int m_primFullUpdateRate = 14; |
114 | protected int m_textureSendLimit = 20; | ||
115 | protected int m_textureDataLimit = 10; | ||
116 | protected int m_avatarTerseUpdateRate = 50; | 317 | protected int m_avatarTerseUpdateRate = 50; |
117 | protected int m_avatarTerseUpdatesPerPacket = 5; | 318 | protected int m_avatarTerseUpdatesPerPacket = 5; |
118 | protected int m_packetMTU = 1400; | 319 | /// <summary>Number of texture packets to put on the queue each time the |
320 | /// OnQueueEmpty event is triggered for the texture category</summary> | ||
321 | protected int m_textureSendLimit = 20; | ||
119 | protected IAssetService m_assetService; | 322 | protected IAssetService m_assetService; |
120 | private IHyperAssetService m_hyperAssets; | 323 | private IHyperAssetService m_hyperAssets; |
121 | 324 | ||
122 | 325 | ||
326 | #endregion Class Members | ||
327 | |||
123 | #region Properties | 328 | #region Properties |
124 | 329 | ||
330 | public LLUDPClient UDPClient { get { return m_udpClient; } } | ||
331 | public IPEndPoint RemoteEndPoint { get { return m_udpClient.RemoteEndPoint; } } | ||
125 | public UUID SecureSessionId { get { return m_secureSessionId; } } | 332 | public UUID SecureSessionId { get { return m_secureSessionId; } } |
126 | public IScene Scene { get { return m_scene; } } | 333 | public IScene Scene { get { return m_scene; } } |
127 | public UUID SessionId { get { return m_sessionId; } } | 334 | public UUID SessionId { get { return m_sessionId; } } |
@@ -202,51 +409,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
202 | #region Client Methods | 409 | #region Client Methods |
203 | 410 | ||
204 | /// <summary> | 411 | /// <summary> |
205 | /// Close down the client view. This *must* be the last method called, since the last # | 412 | /// Shut down the client view |
206 | /// statement of CloseCleanup() aborts the thread. | ||
207 | /// </summary> | 413 | /// </summary> |
208 | /// <param name="shutdownCircuit"></param> | 414 | public void Close() |
209 | public void Close(bool shutdownCircuit) | ||
210 | { | 415 | { |
211 | m_log.DebugFormat( | 416 | m_log.DebugFormat( |
212 | "[CLIENT]: Close has been called with shutdownCircuit = {0} for {1} attached to scene {2}", | 417 | "[CLIENT]: Close has been called for {0} attached to scene {1}", |
213 | shutdownCircuit, Name, m_scene.RegionInfo.RegionName); | 418 | Name, m_scene.RegionInfo.RegionName); |
214 | 419 | ||
420 | // Send the STOP packet | ||
421 | DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); | ||
422 | OutPacket(disable, ThrottleOutPacketType.Unknown); | ||
423 | |||
424 | IsActive = false; | ||
425 | |||
426 | // Shutdown the image manager | ||
215 | if (m_imageManager != null) | 427 | if (m_imageManager != null) |
216 | m_imageManager.Close(); | 428 | m_imageManager.Close(); |
217 | 429 | ||
430 | // Fire the callback for this connection closing | ||
431 | if (OnConnectionClosed != null) | ||
432 | OnConnectionClosed(this); | ||
433 | |||
434 | // Flush all of the packets out of the UDP server for this client | ||
218 | if (m_udpServer != null) | 435 | if (m_udpServer != null) |
219 | m_udpServer.Flush(); | 436 | m_udpServer.Flush(m_udpClient); |
220 | |||
221 | // raise an event on the packet server to Shutdown the circuit | ||
222 | // Now, if we raise the event then the packet server will call this method itself, so don't try cleanup | ||
223 | // here otherwise we'll end up calling it twice. | ||
224 | // FIXME: In truth, I might be wrong but this whole business of calling this method twice (with different args) looks | ||
225 | // horribly tangly. Hopefully it should be possible to greatly simplify it. | ||
226 | if (shutdownCircuit) | ||
227 | { | ||
228 | if (OnConnectionClosed != null) | ||
229 | OnConnectionClosed(this); | ||
230 | } | ||
231 | else | ||
232 | { | ||
233 | CloseCleanup(shutdownCircuit); | ||
234 | } | ||
235 | } | ||
236 | 437 | ||
237 | private void CloseCleanup(bool shutdownCircuit) | 438 | // Remove ourselves from the scene |
238 | { | ||
239 | m_scene.RemoveClient(AgentId); | 439 | m_scene.RemoveClient(AgentId); |
240 | 440 | ||
241 | //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); | ||
242 | //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); | ||
243 | |||
244 | // Send the STOP packet | ||
245 | DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); | ||
246 | OutPacket(disable, ThrottleOutPacketType.Unknown); | ||
247 | |||
248 | Thread.Sleep(2000); | ||
249 | |||
250 | // Shut down timers. Thread Context of this method is murky. Lock all timers | 441 | // Shut down timers. Thread Context of this method is murky. Lock all timers |
251 | if (m_avatarTerseUpdateTimer.Enabled) | 442 | if (m_avatarTerseUpdateTimer.Enabled) |
252 | lock (m_avatarTerseUpdateTimer) | 443 | lock (m_avatarTerseUpdateTimer) |
@@ -258,43 +449,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
258 | lock (m_primFullUpdateTimer) | 449 | lock (m_primFullUpdateTimer) |
259 | m_primFullUpdateTimer.Stop(); | 450 | m_primFullUpdateTimer.Stop(); |
260 | 451 | ||
261 | // This is just to give the client a reasonable chance of | ||
262 | // flushing out all it's packets. There should probably | ||
263 | // be a better mechanism here | ||
264 | |||
265 | // We can't reach into other scenes and close the connection | 452 | // We can't reach into other scenes and close the connection |
266 | // We need to do this over grid communications | 453 | // We need to do this over grid communications |
267 | //m_scene.CloseAllAgents(CircuitCode); | 454 | //m_scene.CloseAllAgents(CircuitCode); |
268 | 455 | ||
269 | // If we're not shutting down the circuit, then this is the last time we'll go here. | 456 | m_avatarTerseUpdateTimer.Dispose(); |
270 | // If we are shutting down the circuit, the UDP Server will come back here with | 457 | m_primTerseUpdateTimer.Dispose(); |
271 | // ShutDownCircuit = false | 458 | m_primFullUpdateTimer.Dispose(); |
272 | if (!(shutdownCircuit)) | ||
273 | { | ||
274 | GC.Collect(); | ||
275 | m_imageManager = null; | ||
276 | // Sends a KillPacket object, with which, the | ||
277 | // blockingqueue dequeues and sees it's a killpacket | ||
278 | // and terminates within the context of the client thread. | ||
279 | // This ensures that it's done from within the context | ||
280 | // of the client thread regardless of where Close() is called. | ||
281 | KillEndDone(); | ||
282 | } | ||
283 | |||
284 | IsActive = false; | ||
285 | |||
286 | m_avatarTerseUpdateTimer.Close(); | ||
287 | m_primTerseUpdateTimer.Close(); | ||
288 | m_primFullUpdateTimer.Close(); | ||
289 | 459 | ||
290 | //m_udpServer.OnPacketStats -= PopulateStats; | 460 | // Disable UDP handling for this client |
291 | m_udpClient.Shutdown(); | 461 | m_udpClient.Shutdown(); |
292 | 462 | ||
293 | // wait for thread stoped | 463 | //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); |
294 | // m_clientThread.Join(); | 464 | //GC.Collect(); |
295 | 465 | //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); | |
296 | // delete circuit code | ||
297 | //m_networkServer.CloseClient(this); | ||
298 | } | 466 | } |
299 | 467 | ||
300 | public void Kick(string message) | 468 | public void Kick(string message) |
@@ -416,43 +584,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
416 | return result; | 584 | return result; |
417 | } | 585 | } |
418 | 586 | ||
419 | /*protected void DebugPacket(string direction, Packet packet) | ||
420 | { | ||
421 | string info; | ||
422 | |||
423 | if (m_debugPacketLevel < 255 && packet.Type == PacketType.AgentUpdate) | ||
424 | return; | ||
425 | if (m_debugPacketLevel < 254 && packet.Type == PacketType.ViewerEffect) | ||
426 | return; | ||
427 | if (m_debugPacketLevel < 253 && ( | ||
428 | packet.Type == PacketType.CompletePingCheck || | ||
429 | packet.Type == PacketType.StartPingCheck | ||
430 | )) | ||
431 | return; | ||
432 | if (m_debugPacketLevel < 252 && packet.Type == PacketType.PacketAck) | ||
433 | return; | ||
434 | |||
435 | if (m_debugPacketLevel > 1) | ||
436 | { | ||
437 | info = packet.ToString(); | ||
438 | } | ||
439 | else | ||
440 | { | ||
441 | info = packet.Type.ToString(); | ||
442 | } | ||
443 | |||
444 | Console.WriteLine(m_circuitCode + ":" + direction + ": " + info); | ||
445 | }*/ | ||
446 | |||
447 | #endregion Packet Handling | 587 | #endregion Packet Handling |
448 | 588 | ||
449 | # region Setup | 589 | # region Setup |
450 | 590 | ||
451 | /// <summary> | 591 | public virtual void Start() |
452 | /// Starts up the timers to check the client and resend unacked packets | ||
453 | /// Adds the client to the OpenSim.Region.Framework.Scenes.Scene | ||
454 | /// </summary> | ||
455 | protected virtual void InitNewClient() | ||
456 | { | 592 | { |
457 | m_avatarTerseUpdateTimer = new Timer(m_avatarTerseUpdateRate); | 593 | m_avatarTerseUpdateTimer = new Timer(m_avatarTerseUpdateRate); |
458 | m_avatarTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates); | 594 | m_avatarTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates); |
@@ -471,262 +607,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
471 | RefreshGroupMembership(); | 607 | RefreshGroupMembership(); |
472 | } | 608 | } |
473 | 609 | ||
474 | public virtual void Start() | ||
475 | { | ||
476 | // This sets up all the timers | ||
477 | InitNewClient(); | ||
478 | } | ||
479 | |||
480 | /// <summary> | ||
481 | /// Run a user session. This method lies at the base of the entire client thread. | ||
482 | /// </summary> | ||
483 | protected void RunUserSession() | ||
484 | { | ||
485 | try | ||
486 | { | ||
487 | |||
488 | } | ||
489 | catch (Exception e) | ||
490 | { | ||
491 | if (e is ThreadAbortException) | ||
492 | throw; | ||
493 | |||
494 | if (StatsManager.SimExtraStats != null) | ||
495 | StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); | ||
496 | |||
497 | // Don't let a failure in an individual client thread crash the whole sim. | ||
498 | m_log.ErrorFormat( | ||
499 | "[CLIENT]: Client thread for {0} {1} crashed. Logging them out.", Name, AgentId); | ||
500 | m_log.Error(e.ToString()); | ||
501 | |||
502 | try | ||
503 | { | ||
504 | // Make an attempt to alert the user that their session has crashed | ||
505 | AgentAlertMessagePacket packet | ||
506 | = BuildAgentAlertPacket( | ||
507 | "Unfortunately the session for this client on the server has crashed.\n" | ||
508 | + "Any further actions taken will not be processed.\n" | ||
509 | + "Please relog", true); | ||
510 | |||
511 | m_udpServer.SendPacket(m_agentId, packet, ThrottleOutPacketType.Unknown, false); | ||
512 | |||
513 | // There may be a better way to do this. Perhaps kick? Not sure this propogates notifications to | ||
514 | // listeners yet, though. | ||
515 | Logout(this); | ||
516 | } | ||
517 | catch (Exception e2) | ||
518 | { | ||
519 | if (e2 is ThreadAbortException) | ||
520 | throw; | ||
521 | |||
522 | m_log.ErrorFormat("[CLIENT]: Further exception thrown on forced session logout. {0}", e2); | ||
523 | } | ||
524 | } | ||
525 | } | ||
526 | |||
527 | # endregion | 610 | # endregion |
528 | 611 | ||
529 | #region Events | ||
530 | |||
531 | public event GenericMessage OnGenericMessage; | ||
532 | public event BinaryGenericMessage OnBinaryGenericMessage; | ||
533 | public event Action<IClientAPI> OnLogout; | ||
534 | public event ObjectPermissions OnObjectPermissions; | ||
535 | public event Action<IClientAPI> OnConnectionClosed; | ||
536 | public event ViewerEffectEventHandler OnViewerEffect; | ||
537 | public event ImprovedInstantMessage OnInstantMessage; | ||
538 | public event ChatMessage OnChatFromClient; | ||
539 | public event TextureRequest OnRequestTexture; | ||
540 | public event RezObject OnRezObject; | ||
541 | public event DeRezObject OnDeRezObject; | ||
542 | public event ModifyTerrain OnModifyTerrain; | ||
543 | public event Action<IClientAPI> OnRegionHandShakeReply; | ||
544 | public event GenericCall2 OnRequestWearables; | ||
545 | public event SetAppearance OnSetAppearance; | ||
546 | public event AvatarNowWearing OnAvatarNowWearing; | ||
547 | public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; | ||
548 | public event RezMultipleAttachmentsFromInv OnRezMultipleAttachmentsFromInv; | ||
549 | public event UUIDNameRequest OnDetachAttachmentIntoInv; | ||
550 | public event ObjectAttach OnObjectAttach; | ||
551 | public event ObjectDeselect OnObjectDetach; | ||
552 | public event ObjectDrop OnObjectDrop; | ||
553 | public event GenericCall2 OnCompleteMovementToRegion; | ||
554 | public event UpdateAgent OnAgentUpdate; | ||
555 | public event AgentRequestSit OnAgentRequestSit; | ||
556 | public event AgentSit OnAgentSit; | ||
557 | public event AvatarPickerRequest OnAvatarPickerRequest; | ||
558 | public event StartAnim OnStartAnim; | ||
559 | public event StopAnim OnStopAnim; | ||
560 | public event Action<IClientAPI> OnRequestAvatarsData; | ||
561 | public event LinkObjects OnLinkObjects; | ||
562 | public event DelinkObjects OnDelinkObjects; | ||
563 | public event GrabObject OnGrabObject; | ||
564 | public event DeGrabObject OnDeGrabObject; | ||
565 | public event SpinStart OnSpinStart; | ||
566 | public event SpinStop OnSpinStop; | ||
567 | public event ObjectDuplicate OnObjectDuplicate; | ||
568 | public event ObjectDuplicateOnRay OnObjectDuplicateOnRay; | ||
569 | public event MoveObject OnGrabUpdate; | ||
570 | public event SpinObject OnSpinUpdate; | ||
571 | public event AddNewPrim OnAddPrim; | ||
572 | public event RequestGodlikePowers OnRequestGodlikePowers; | ||
573 | public event GodKickUser OnGodKickUser; | ||
574 | public event ObjectExtraParams OnUpdateExtraParams; | ||
575 | public event UpdateShape OnUpdatePrimShape; | ||
576 | public event ObjectRequest OnObjectRequest; | ||
577 | public event ObjectSelect OnObjectSelect; | ||
578 | public event ObjectDeselect OnObjectDeselect; | ||
579 | public event GenericCall7 OnObjectDescription; | ||
580 | public event GenericCall7 OnObjectName; | ||
581 | public event GenericCall7 OnObjectClickAction; | ||
582 | public event GenericCall7 OnObjectMaterial; | ||
583 | public event ObjectIncludeInSearch OnObjectIncludeInSearch; | ||
584 | public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; | ||
585 | public event UpdatePrimFlags OnUpdatePrimFlags; | ||
586 | public event UpdatePrimTexture OnUpdatePrimTexture; | ||
587 | public event UpdateVector OnUpdatePrimGroupPosition; | ||
588 | public event UpdateVector OnUpdatePrimSinglePosition; | ||
589 | public event UpdatePrimRotation OnUpdatePrimGroupRotation; | ||
590 | public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation; | ||
591 | public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition; | ||
592 | public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation; | ||
593 | public event UpdateVector OnUpdatePrimScale; | ||
594 | public event UpdateVector OnUpdatePrimGroupScale; | ||
595 | public event StatusChange OnChildAgentStatus; | ||
596 | public event GenericCall2 OnStopMovement; | ||
597 | public event Action<UUID> OnRemoveAvatar; | ||
598 | public event RequestMapBlocks OnRequestMapBlocks; | ||
599 | public event RequestMapName OnMapNameRequest; | ||
600 | public event TeleportLocationRequest OnTeleportLocationRequest; | ||
601 | public event TeleportLandmarkRequest OnTeleportLandmarkRequest; | ||
602 | public event DisconnectUser OnDisconnectUser; | ||
603 | public event RequestAvatarProperties OnRequestAvatarProperties; | ||
604 | public event SetAlwaysRun OnSetAlwaysRun; | ||
605 | public event FetchInventory OnAgentDataUpdateRequest; | ||
606 | public event TeleportLocationRequest OnSetStartLocationRequest; | ||
607 | public event UpdateAvatarProperties OnUpdateAvatarProperties; | ||
608 | public event CreateNewInventoryItem OnCreateNewInventoryItem; | ||
609 | public event CreateInventoryFolder OnCreateNewInventoryFolder; | ||
610 | public event UpdateInventoryFolder OnUpdateInventoryFolder; | ||
611 | public event MoveInventoryFolder OnMoveInventoryFolder; | ||
612 | public event FetchInventoryDescendents OnFetchInventoryDescendents; | ||
613 | public event PurgeInventoryDescendents OnPurgeInventoryDescendents; | ||
614 | public event FetchInventory OnFetchInventory; | ||
615 | public event RequestTaskInventory OnRequestTaskInventory; | ||
616 | public event UpdateInventoryItem OnUpdateInventoryItem; | ||
617 | public event CopyInventoryItem OnCopyInventoryItem; | ||
618 | public event MoveInventoryItem OnMoveInventoryItem; | ||
619 | public event RemoveInventoryItem OnRemoveInventoryItem; | ||
620 | public event RemoveInventoryFolder OnRemoveInventoryFolder; | ||
621 | public event UDPAssetUploadRequest OnAssetUploadRequest; | ||
622 | public event XferReceive OnXferReceive; | ||
623 | public event RequestXfer OnRequestXfer; | ||
624 | public event ConfirmXfer OnConfirmXfer; | ||
625 | public event AbortXfer OnAbortXfer; | ||
626 | public event RequestTerrain OnRequestTerrain; | ||
627 | public event RezScript OnRezScript; | ||
628 | public event UpdateTaskInventory OnUpdateTaskInventory; | ||
629 | public event MoveTaskInventory OnMoveTaskItem; | ||
630 | public event RemoveTaskInventory OnRemoveTaskItem; | ||
631 | public event RequestAsset OnRequestAsset; | ||
632 | public event UUIDNameRequest OnNameFromUUIDRequest; | ||
633 | public event ParcelAccessListRequest OnParcelAccessListRequest; | ||
634 | public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest; | ||
635 | public event ParcelPropertiesRequest OnParcelPropertiesRequest; | ||
636 | public event ParcelDivideRequest OnParcelDivideRequest; | ||
637 | public event ParcelJoinRequest OnParcelJoinRequest; | ||
638 | public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest; | ||
639 | public event ParcelSelectObjects OnParcelSelectObjects; | ||
640 | public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest; | ||
641 | public event ParcelAbandonRequest OnParcelAbandonRequest; | ||
642 | public event ParcelGodForceOwner OnParcelGodForceOwner; | ||
643 | public event ParcelReclaim OnParcelReclaim; | ||
644 | public event ParcelReturnObjectsRequest OnParcelReturnObjectsRequest; | ||
645 | public event ParcelDeedToGroup OnParcelDeedToGroup; | ||
646 | public event RegionInfoRequest OnRegionInfoRequest; | ||
647 | public event EstateCovenantRequest OnEstateCovenantRequest; | ||
648 | public event FriendActionDelegate OnApproveFriendRequest; | ||
649 | public event FriendActionDelegate OnDenyFriendRequest; | ||
650 | public event FriendshipTermination OnTerminateFriendship; | ||
651 | public event MoneyTransferRequest OnMoneyTransferRequest; | ||
652 | public event EconomyDataRequest OnEconomyDataRequest; | ||
653 | public event MoneyBalanceRequest OnMoneyBalanceRequest; | ||
654 | public event ParcelBuy OnParcelBuy; | ||
655 | public event UUIDNameRequest OnTeleportHomeRequest; | ||
656 | public event UUIDNameRequest OnUUIDGroupNameRequest; | ||
657 | public event ScriptAnswer OnScriptAnswer; | ||
658 | public event RequestPayPrice OnRequestPayPrice; | ||
659 | public event ObjectSaleInfo OnObjectSaleInfo; | ||
660 | public event ObjectBuy OnObjectBuy; | ||
661 | public event BuyObjectInventory OnBuyObjectInventory; | ||
662 | public event AgentSit OnUndo; | ||
663 | public event ForceReleaseControls OnForceReleaseControls; | ||
664 | public event GodLandStatRequest OnLandStatRequest; | ||
665 | public event RequestObjectPropertiesFamily OnObjectGroupRequest; | ||
666 | public event DetailedEstateDataRequest OnDetailedEstateDataRequest; | ||
667 | public event SetEstateFlagsRequest OnSetEstateFlagsRequest; | ||
668 | public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture; | ||
669 | public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture; | ||
670 | public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights; | ||
671 | public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest; | ||
672 | public event SetRegionTerrainSettings OnSetRegionTerrainSettings; | ||
673 | public event BakeTerrain OnBakeTerrain; | ||
674 | public event RequestTerrain OnUploadTerrain; | ||
675 | public event EstateChangeInfo OnEstateChangeInfo; | ||
676 | public event EstateRestartSimRequest OnEstateRestartSimRequest; | ||
677 | public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest; | ||
678 | public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest; | ||
679 | public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest; | ||
680 | public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest; | ||
681 | public event EstateDebugRegionRequest OnEstateDebugRegionRequest; | ||
682 | public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest; | ||
683 | public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; | ||
684 | public event RegionHandleRequest OnRegionHandleRequest; | ||
685 | public event ParcelInfoRequest OnParcelInfoRequest; | ||
686 | public event ScriptReset OnScriptReset; | ||
687 | public event GetScriptRunning OnGetScriptRunning; | ||
688 | public event SetScriptRunning OnSetScriptRunning; | ||
689 | public event UpdateVector OnAutoPilotGo; | ||
690 | public event TerrainUnacked OnUnackedTerrain; | ||
691 | public event ActivateGesture OnActivateGesture; | ||
692 | public event DeactivateGesture OnDeactivateGesture; | ||
693 | public event ObjectOwner OnObjectOwner; | ||
694 | public event DirPlacesQuery OnDirPlacesQuery; | ||
695 | public event DirFindQuery OnDirFindQuery; | ||
696 | public event DirLandQuery OnDirLandQuery; | ||
697 | public event DirPopularQuery OnDirPopularQuery; | ||
698 | public event DirClassifiedQuery OnDirClassifiedQuery; | ||
699 | public event EventInfoRequest OnEventInfoRequest; | ||
700 | public event ParcelSetOtherCleanTime OnParcelSetOtherCleanTime; | ||
701 | public event MapItemRequest OnMapItemRequest; | ||
702 | public event OfferCallingCard OnOfferCallingCard; | ||
703 | public event AcceptCallingCard OnAcceptCallingCard; | ||
704 | public event DeclineCallingCard OnDeclineCallingCard; | ||
705 | public event SoundTrigger OnSoundTrigger; | ||
706 | public event StartLure OnStartLure; | ||
707 | public event TeleportLureRequest OnTeleportLureRequest; | ||
708 | public event NetworkStats OnNetworkStatsUpdate; | ||
709 | public event ClassifiedInfoRequest OnClassifiedInfoRequest; | ||
710 | public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; | ||
711 | public event ClassifiedDelete OnClassifiedDelete; | ||
712 | public event ClassifiedDelete OnClassifiedGodDelete; | ||
713 | public event EventNotificationAddRequest OnEventNotificationAddRequest; | ||
714 | public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; | ||
715 | public event EventGodDelete OnEventGodDelete; | ||
716 | public event ParcelDwellRequest OnParcelDwellRequest; | ||
717 | public event UserInfoRequest OnUserInfoRequest; | ||
718 | public event UpdateUserInfo OnUpdateUserInfo; | ||
719 | public event RetrieveInstantMessages OnRetrieveInstantMessages; | ||
720 | public event PickDelete OnPickDelete; | ||
721 | public event PickGodDelete OnPickGodDelete; | ||
722 | public event PickInfoUpdate OnPickInfoUpdate; | ||
723 | public event AvatarNotesUpdate OnAvatarNotesUpdate; | ||
724 | public event MuteListRequest OnMuteListRequest; | ||
725 | public event AvatarInterestUpdate OnAvatarInterestUpdate; | ||
726 | public event PlacesQuery OnPlacesQuery; | ||
727 | |||
728 | #endregion Events | ||
729 | |||
730 | public void ActivateGesture(UUID assetId, UUID gestureId) | 612 | public void ActivateGesture(UUID assetId, UUID gestureId) |
731 | { | 613 | { |
732 | } | 614 | } |
@@ -1346,7 +1228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1346 | kill.ObjectData[0].ID = localID; | 1228 | kill.ObjectData[0].ID = localID; |
1347 | kill.Header.Reliable = true; | 1229 | kill.Header.Reliable = true; |
1348 | kill.Header.Zerocoded = true; | 1230 | kill.Header.Zerocoded = true; |
1349 | OutPacket(kill, ThrottleOutPacketType.Task); | 1231 | OutPacket(kill, ThrottleOutPacketType.State); |
1350 | } | 1232 | } |
1351 | 1233 | ||
1352 | /// <summary> | 1234 | /// <summary> |
@@ -1940,7 +1822,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1940 | sendXfer.XferID.ID = xferID; | 1822 | sendXfer.XferID.ID = xferID; |
1941 | sendXfer.XferID.Packet = packet; | 1823 | sendXfer.XferID.Packet = packet; |
1942 | sendXfer.DataPacket.Data = data; | 1824 | sendXfer.DataPacket.Data = data; |
1943 | OutPacket(sendXfer, ThrottleOutPacketType.Task); | 1825 | OutPacket(sendXfer, ThrottleOutPacketType.Asset); |
1944 | } | 1826 | } |
1945 | 1827 | ||
1946 | public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, | 1828 | public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, |
@@ -2222,7 +2104,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2222 | packet.AgentData.SessionID = SessionId; | 2104 | packet.AgentData.SessionID = SessionId; |
2223 | packet.Header.Reliable = false; | 2105 | packet.Header.Reliable = false; |
2224 | packet.Header.Zerocoded = true; | 2106 | packet.Header.Zerocoded = true; |
2225 | OutPacket(packet, ThrottleOutPacketType.Task); | 2107 | OutPacket(packet, ThrottleOutPacketType.State); |
2226 | } | 2108 | } |
2227 | 2109 | ||
2228 | public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, | 2110 | public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, |
@@ -3245,7 +3127,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3245 | 3127 | ||
3246 | avp.Sender.IsTrial = false; | 3128 | avp.Sender.IsTrial = false; |
3247 | avp.Sender.ID = agentID; | 3129 | avp.Sender.ID = agentID; |
3248 | OutPacket(avp, ThrottleOutPacketType.Task); | 3130 | OutPacket(avp, ThrottleOutPacketType.State); |
3249 | } | 3131 | } |
3250 | 3132 | ||
3251 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) | 3133 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) |
@@ -3370,7 +3252,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3370 | int length = 0; | 3252 | int length = 0; |
3371 | m_avatarTerseUpdates[count].ToBytes(blockbuffer, ref length); | 3253 | m_avatarTerseUpdates[count].ToBytes(blockbuffer, ref length); |
3372 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | 3254 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); |
3373 | if (size + length > m_packetMTU) | 3255 | if (size + length > Packet.MTU) |
3374 | break; | 3256 | break; |
3375 | size += length; | 3257 | size += length; |
3376 | } | 3258 | } |
@@ -3385,6 +3267,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3385 | 3267 | ||
3386 | terse.Header.Reliable = false; | 3268 | terse.Header.Reliable = false; |
3387 | terse.Header.Zerocoded = true; | 3269 | terse.Header.Zerocoded = true; |
3270 | // FIXME: Move this to ThrottleOutPacketType.State when the real prioritization code is committed | ||
3388 | OutPacket(terse, ThrottleOutPacketType.Task); | 3271 | OutPacket(terse, ThrottleOutPacketType.Task); |
3389 | 3272 | ||
3390 | if (m_avatarTerseUpdates.Count == 0) | 3273 | if (m_avatarTerseUpdates.Count == 0) |
@@ -3575,7 +3458,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3575 | void ProcessTextureRequests() | 3458 | void ProcessTextureRequests() |
3576 | { | 3459 | { |
3577 | if (m_imageManager != null) | 3460 | if (m_imageManager != null) |
3578 | m_imageManager.ProcessImageQueue(m_textureSendLimit, m_textureDataLimit); | 3461 | m_imageManager.ProcessImageQueue(m_textureSendLimit); |
3579 | } | 3462 | } |
3580 | 3463 | ||
3581 | void ProcessPrimFullUpdates(object sender, ElapsedEventArgs e) | 3464 | void ProcessPrimFullUpdates(object sender, ElapsedEventArgs e) |
@@ -3614,7 +3497,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3614 | int length = 0; | 3497 | int length = 0; |
3615 | m_primFullUpdates[count].ToBytes(blockbuffer, ref length); | 3498 | m_primFullUpdates[count].ToBytes(blockbuffer, ref length); |
3616 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | 3499 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); |
3617 | if (size + length > m_packetMTU) | 3500 | if (size + length > Packet.MTU) |
3618 | break; | 3501 | break; |
3619 | size += length; | 3502 | size += length; |
3620 | } | 3503 | } |
@@ -3629,7 +3512,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3629 | } | 3512 | } |
3630 | 3513 | ||
3631 | outPacket.Header.Zerocoded = true; | 3514 | outPacket.Header.Zerocoded = true; |
3632 | OutPacket(outPacket, ThrottleOutPacketType.Task); | 3515 | OutPacket(outPacket, ThrottleOutPacketType.State); |
3633 | 3516 | ||
3634 | if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) | 3517 | if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) |
3635 | lock (m_primFullUpdateTimer) | 3518 | lock (m_primFullUpdateTimer) |
@@ -3702,7 +3585,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3702 | int length = 0; | 3585 | int length = 0; |
3703 | m_primTerseUpdates[count].ToBytes(blockbuffer, ref length); | 3586 | m_primTerseUpdates[count].ToBytes(blockbuffer, ref length); |
3704 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | 3587 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); |
3705 | if (size + length > m_packetMTU) | 3588 | if (size + length > Packet.MTU) |
3706 | break; | 3589 | break; |
3707 | size += length; | 3590 | size += length; |
3708 | } | 3591 | } |
@@ -3719,7 +3602,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3719 | 3602 | ||
3720 | outPacket.Header.Reliable = false; | 3603 | outPacket.Header.Reliable = false; |
3721 | outPacket.Header.Zerocoded = true; | 3604 | outPacket.Header.Zerocoded = true; |
3722 | OutPacket(outPacket, ThrottleOutPacketType.Task); | 3605 | OutPacket(outPacket, ThrottleOutPacketType.State); |
3723 | 3606 | ||
3724 | if (m_primTerseUpdates.Count == 0) | 3607 | if (m_primTerseUpdates.Count == 0) |
3725 | lock (m_primTerseUpdateTimer) | 3608 | lock (m_primTerseUpdateTimer) |
@@ -4805,7 +4688,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4805 | 4688 | ||
4806 | public bool HandleObjectGroupRequest(IClientAPI sender, Packet Pack) | 4689 | public bool HandleObjectGroupRequest(IClientAPI sender, Packet Pack) |
4807 | { | 4690 | { |
4808 | |||
4809 | ObjectGroupPacket ogpack = (ObjectGroupPacket)Pack; | 4691 | ObjectGroupPacket ogpack = (ObjectGroupPacket)Pack; |
4810 | if (ogpack.AgentData.SessionID != SessionId) return false; | 4692 | if (ogpack.AgentData.SessionID != SessionId) return false; |
4811 | 4693 | ||
@@ -10252,7 +10134,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10252 | 10134 | ||
10253 | public void KillEndDone() | 10135 | public void KillEndDone() |
10254 | { | 10136 | { |
10255 | m_udpClient.Shutdown(); | ||
10256 | } | 10137 | } |
10257 | 10138 | ||
10258 | #region IClientCore | 10139 | #region IClientCore |
@@ -10295,15 +10176,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10295 | { | 10176 | { |
10296 | Kick(reason); | 10177 | Kick(reason); |
10297 | Thread.Sleep(1000); | 10178 | Thread.Sleep(1000); |
10298 | Close(true); | 10179 | Close(); |
10299 | } | 10180 | } |
10300 | 10181 | ||
10301 | public void Disconnect() | 10182 | public void Disconnect() |
10302 | { | 10183 | { |
10303 | Close(true); | 10184 | Close(); |
10304 | } | 10185 | } |
10305 | 10186 | ||
10306 | |||
10307 | #endregion | 10187 | #endregion |
10308 | 10188 | ||
10309 | public void RefreshGroupMembership() | 10189 | public void RefreshGroupMembership() |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs index 56d34e6..d25bf95 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs | |||
@@ -167,47 +167,48 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
167 | } | 167 | } |
168 | } | 168 | } |
169 | 169 | ||
170 | public bool ProcessImageQueue(int count, int maxpack) | 170 | public bool ProcessImageQueue(int packetsToSend) |
171 | { | 171 | { |
172 | J2KImage imagereq; | 172 | m_lastloopprocessed = DateTime.Now.Ticks; |
173 | int numCollected = 0; | 173 | int packetsSent = 0; |
174 | 174 | ||
175 | //lock (m_syncRoot) | 175 | while (packetsSent < packetsToSend) |
176 | //{ | 176 | { |
177 | m_lastloopprocessed = DateTime.Now.Ticks; | 177 | J2KImage image = GetHighestPriorityImage(); |
178 | 178 | ||
179 | // This can happen during Close() | 179 | // If null was returned, the texture priority queue is currently empty |
180 | if (m_client == null) | 180 | if (image == null) |
181 | return false; | 181 | return false; |
182 | |||
183 | while ((imagereq = GetHighestPriorityImage()) != null) | ||
184 | { | ||
185 | if (imagereq.IsDecoded == true) | ||
186 | { | ||
187 | ++numCollected; | ||
188 | 182 | ||
189 | if (imagereq.SendPackets(m_client, maxpack)) | 183 | if (image.IsDecoded) |
190 | { | 184 | { |
191 | // Send complete. Destroy any knowledge of this transfer | 185 | int sent; |
192 | RemoveImageFromQueue(imagereq); | 186 | bool imageDone = image.SendPackets(m_client, packetsToSend - packetsSent, out sent); |
193 | } | 187 | packetsSent += sent; |
194 | } | ||
195 | 188 | ||
196 | if (numCollected == count) | 189 | // If the send is complete, destroy any knowledge of this transfer |
197 | break; | 190 | if (imageDone) |
191 | RemoveImageFromQueue(image); | ||
198 | } | 192 | } |
199 | //} | 193 | else |
194 | { | ||
195 | // TODO: This is a limitation of how LLImageManager is currently | ||
196 | // written. Undecoded textures should not be going into the priority | ||
197 | // queue, because a high priority undecoded texture will clog up the | ||
198 | // pipeline for a client | ||
199 | return true; | ||
200 | } | ||
201 | } | ||
200 | 202 | ||
201 | return m_priorityQueue.Count > 0; | 203 | return m_priorityQueue.Count > 0; |
202 | } | 204 | } |
203 | 205 | ||
204 | //Faux destructor | 206 | /// <summary> |
207 | /// Faux destructor | ||
208 | /// </summary> | ||
205 | public void Close() | 209 | public void Close() |
206 | { | 210 | { |
207 | m_shuttingdown = true; | 211 | m_shuttingdown = true; |
208 | m_j2kDecodeModule = null; | ||
209 | m_assetCache = null; | ||
210 | m_client = null; | ||
211 | } | 212 | } |
212 | 213 | ||
213 | #region Priority Queue Helpers | 214 | #region Priority Queue Helpers |
@@ -218,13 +219,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
218 | 219 | ||
219 | lock (m_syncRoot) | 220 | lock (m_syncRoot) |
220 | { | 221 | { |
221 | |||
222 | if (m_priorityQueue.Count > 0) | 222 | if (m_priorityQueue.Count > 0) |
223 | { | 223 | { |
224 | try | 224 | try { image = m_priorityQueue.FindMax(); } |
225 | { | ||
226 | image = m_priorityQueue.FindMax(); | ||
227 | } | ||
228 | catch (Exception) { } | 225 | catch (Exception) { } |
229 | } | 226 | } |
230 | } | 227 | } |
@@ -236,20 +233,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
236 | image.PriorityQueueHandle = null; | 233 | image.PriorityQueueHandle = null; |
237 | 234 | ||
238 | lock (m_syncRoot) | 235 | lock (m_syncRoot) |
239 | try | 236 | try { m_priorityQueue.Add(ref image.PriorityQueueHandle, image); } |
240 | { | ||
241 | m_priorityQueue.Add(ref image.PriorityQueueHandle, image); | ||
242 | } | ||
243 | catch (Exception) { } | 237 | catch (Exception) { } |
244 | } | 238 | } |
245 | 239 | ||
246 | void RemoveImageFromQueue(J2KImage image) | 240 | void RemoveImageFromQueue(J2KImage image) |
247 | { | 241 | { |
248 | lock (m_syncRoot) | 242 | lock (m_syncRoot) |
249 | try | 243 | try { m_priorityQueue.Delete(image.PriorityQueueHandle); } |
250 | { | ||
251 | m_priorityQueue.Delete(image.PriorityQueueHandle); | ||
252 | } | ||
253 | catch (Exception) { } | 244 | catch (Exception) { } |
254 | } | 245 | } |
255 | 246 | ||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 871e8e8..4eee6b6 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | |||
@@ -28,8 +28,10 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Net; | 30 | using System.Net; |
31 | using log4net; | ||
31 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
32 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenMetaverse.Packets; | ||
33 | 35 | ||
34 | namespace OpenSim.Region.ClientStack.LindenUDP | 36 | namespace OpenSim.Region.ClientStack.LindenUDP |
35 | { | 37 | { |
@@ -59,9 +61,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
59 | /// </summary> | 61 | /// </summary> |
60 | public sealed class LLUDPClient | 62 | public sealed class LLUDPClient |
61 | { | 63 | { |
64 | // TODO: Make this a config setting | ||
65 | /// <summary>Percentage of the task throttle category that is allocated to avatar and prim | ||
66 | /// state updates</summary> | ||
67 | const float STATE_TASK_PERCENTAGE = 0.8f; | ||
68 | |||
69 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
70 | |||
62 | /// <summary>The number of packet categories to throttle on. If a throttle category is added | 71 | /// <summary>The number of packet categories to throttle on. If a throttle category is added |
63 | /// or removed, this number must also change</summary> | 72 | /// or removed, this number must also change</summary> |
64 | const int THROTTLE_CATEGORY_COUNT = 7; | 73 | const int THROTTLE_CATEGORY_COUNT = 8; |
65 | 74 | ||
66 | /// <summary>Fired when updated networking stats are produced for this client</summary> | 75 | /// <summary>Fired when updated networking stats are produced for this client</summary> |
67 | public event PacketStats OnPacketStats; | 76 | public event PacketStats OnPacketStats; |
@@ -80,10 +89,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
80 | /// <summary>Packets we have sent that need to be ACKed by the client</summary> | 89 | /// <summary>Packets we have sent that need to be ACKed by the client</summary> |
81 | public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); | 90 | public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); |
82 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> | 91 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> |
83 | public readonly LocklessQueue<uint> PendingAcks = new LocklessQueue<uint>(); | 92 | public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>(); |
84 | 93 | ||
85 | /// <summary>Reference to the IClientAPI for this client</summary> | ||
86 | public LLClientView ClientAPI; | ||
87 | /// <summary>Current packet sequence number</summary> | 94 | /// <summary>Current packet sequence number</summary> |
88 | public int CurrentSequence; | 95 | public int CurrentSequence; |
89 | /// <summary>Current ping sequence number</summary> | 96 | /// <summary>Current ping sequence number</summary> |
@@ -123,21 +130,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
123 | private int m_packetsSentReported; | 130 | private int m_packetsSentReported; |
124 | 131 | ||
125 | /// <summary>Throttle bucket for this agent's connection</summary> | 132 | /// <summary>Throttle bucket for this agent's connection</summary> |
126 | private readonly TokenBucket throttle; | 133 | private readonly TokenBucket m_throttle; |
127 | /// <summary>Throttle buckets for each packet category</summary> | 134 | /// <summary>Throttle buckets for each packet category</summary> |
128 | private readonly TokenBucket[] throttleCategories; | 135 | private readonly TokenBucket[] m_throttleCategories; |
129 | /// <summary>Throttle rate defaults and limits</summary> | 136 | /// <summary>Throttle rate defaults and limits</summary> |
130 | private readonly ThrottleRates defaultThrottleRates; | 137 | private readonly ThrottleRates m_defaultThrottleRates; |
131 | /// <summary>Outgoing queues for throttled packets</summary> | 138 | /// <summary>Outgoing queues for throttled packets</summary> |
132 | private readonly LocklessQueue<OutgoingPacket>[] packetOutboxes = new LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; | 139 | private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; |
133 | /// <summary>A container that can hold one packet for each outbox, used to store | 140 | /// <summary>A container that can hold one packet for each outbox, used to store |
134 | /// dequeued packets that are being held for throttling</summary> | 141 | /// dequeued packets that are being held for throttling</summary> |
135 | private readonly OutgoingPacket[] nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; | 142 | private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; |
136 | /// <summary>An optimization to store the length of dequeued packets being held | 143 | /// <summary>Flags to prevent queue empty callbacks from stacking up on |
137 | /// for throttling. This avoids expensive calls to Packet.Length</summary> | 144 | /// top of each other</summary> |
138 | private readonly int[] nextPacketLengths = new int[THROTTLE_CATEGORY_COUNT]; | 145 | private readonly bool[] m_onQueueEmptyRunning = new bool[THROTTLE_CATEGORY_COUNT]; |
139 | /// <summary>A reference to the LLUDPServer that is managing this client</summary> | 146 | /// <summary>A reference to the LLUDPServer that is managing this client</summary> |
140 | private readonly LLUDPServer udpServer; | 147 | private readonly LLUDPServer m_udpServer; |
141 | 148 | ||
142 | /// <summary> | 149 | /// <summary> |
143 | /// Default constructor | 150 | /// Default constructor |
@@ -151,24 +158,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
151 | /// <param name="remoteEndPoint">Remote endpoint for this connection</param> | 158 | /// <param name="remoteEndPoint">Remote endpoint for this connection</param> |
152 | public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint) | 159 | public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint) |
153 | { | 160 | { |
154 | udpServer = server; | ||
155 | AgentID = agentID; | 161 | AgentID = agentID; |
156 | RemoteEndPoint = remoteEndPoint; | 162 | RemoteEndPoint = remoteEndPoint; |
157 | CircuitCode = circuitCode; | 163 | CircuitCode = circuitCode; |
158 | defaultThrottleRates = rates; | 164 | m_udpServer = server; |
165 | m_defaultThrottleRates = rates; | ||
166 | m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); | ||
167 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | ||
159 | 168 | ||
160 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 169 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
161 | packetOutboxes[i] = new LocklessQueue<OutgoingPacket>(); | 170 | { |
162 | 171 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; | |
163 | throttle = new TokenBucket(parentThrottle, 0, 0); | 172 | |
164 | throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | 173 | m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); |
165 | throttleCategories[(int)ThrottleOutPacketType.Resend] = new TokenBucket(throttle, rates.ResendLimit, rates.Resend); | 174 | m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); |
166 | throttleCategories[(int)ThrottleOutPacketType.Land] = new TokenBucket(throttle, rates.LandLimit, rates.Land); | 175 | } |
167 | throttleCategories[(int)ThrottleOutPacketType.Wind] = new TokenBucket(throttle, rates.WindLimit, rates.Wind); | ||
168 | throttleCategories[(int)ThrottleOutPacketType.Cloud] = new TokenBucket(throttle, rates.CloudLimit, rates.Cloud); | ||
169 | throttleCategories[(int)ThrottleOutPacketType.Task] = new TokenBucket(throttle, rates.TaskLimit, rates.Task); | ||
170 | throttleCategories[(int)ThrottleOutPacketType.Texture] = new TokenBucket(throttle, rates.TextureLimit, rates.Texture); | ||
171 | throttleCategories[(int)ThrottleOutPacketType.Asset] = new TokenBucket(throttle, rates.AssetLimit, rates.Asset); | ||
172 | 176 | ||
173 | // Set the granularity variable used for retransmission calculations to | 177 | // Set the granularity variable used for retransmission calculations to |
174 | // the measured resolution of Environment.TickCount | 178 | // the measured resolution of Environment.TickCount |
@@ -176,6 +180,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
176 | 180 | ||
177 | // Default the retransmission timeout to three seconds | 181 | // Default the retransmission timeout to three seconds |
178 | RTO = 3000; | 182 | RTO = 3000; |
183 | |||
184 | // Initialize this to a sane value to prevent early disconnects | ||
185 | TickLastPacketReceived = Environment.TickCount; | ||
179 | } | 186 | } |
180 | 187 | ||
181 | /// <summary> | 188 | /// <summary> |
@@ -183,8 +190,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
183 | /// </summary> | 190 | /// </summary> |
184 | public void Shutdown() | 191 | public void Shutdown() |
185 | { | 192 | { |
186 | // TODO: Do we need to invalidate the circuit? | ||
187 | IsConnected = false; | 193 | IsConnected = false; |
194 | NeedAcks.Clear(); | ||
195 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | ||
196 | { | ||
197 | m_packetOutboxes[i].Clear(); | ||
198 | m_nextPackets[i] = null; | ||
199 | } | ||
200 | OnPacketStats = null; | ||
201 | OnQueueEmpty = null; | ||
188 | } | 202 | } |
189 | 203 | ||
190 | /// <summary> | 204 | /// <summary> |
@@ -200,13 +214,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
200 | info.pendingAcks = new Dictionary<uint, uint>(); | 214 | info.pendingAcks = new Dictionary<uint, uint>(); |
201 | info.needAck = new Dictionary<uint, byte[]>(); | 215 | info.needAck = new Dictionary<uint, byte[]>(); |
202 | 216 | ||
203 | info.resendThrottle = throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; | 217 | info.resendThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; |
204 | info.landThrottle = throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; | 218 | info.landThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; |
205 | info.windThrottle = throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | 219 | info.windThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; |
206 | info.cloudThrottle = throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; | 220 | info.cloudThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; |
207 | info.taskThrottle = throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; | 221 | info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; |
208 | info.assetThrottle = throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; | 222 | info.assetThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; |
209 | info.textureThrottle = throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | 223 | info.textureThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; |
210 | info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + | 224 | info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + |
211 | info.taskThrottle + info.assetThrottle + info.textureThrottle; | 225 | info.taskThrottle + info.assetThrottle + info.textureThrottle; |
212 | 226 | ||
@@ -267,6 +281,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
267 | adjData = throttleData; | 281 | adjData = throttleData; |
268 | } | 282 | } |
269 | 283 | ||
284 | // 0.125f converts from bits to bytes | ||
270 | int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 285 | int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; |
271 | int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 286 | int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; |
272 | int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 287 | int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; |
@@ -274,22 +289,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
274 | int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 289 | int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; |
275 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 290 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; |
276 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | 291 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); |
292 | // State is a subcategory of task that we allocate a percentage to | ||
293 | int state = (int)((float)task * STATE_TASK_PERCENTAGE); | ||
294 | task -= state; | ||
295 | |||
296 | int ceiling = Int32.MaxValue; | ||
297 | if (m_defaultThrottleRates.Total != 0) | ||
298 | { | ||
299 | ceiling = m_defaultThrottleRates.Total; | ||
300 | if (ceiling < Packet.MTU) ceiling = Packet.MTU; | ||
301 | } | ||
277 | 302 | ||
278 | resend = (resend <= defaultThrottleRates.ResendLimit) ? resend : defaultThrottleRates.ResendLimit; | 303 | resend = Utils.Clamp(resend, Packet.MTU, ceiling); |
279 | land = (land <= defaultThrottleRates.LandLimit) ? land : defaultThrottleRates.LandLimit; | 304 | land = Utils.Clamp(land, Packet.MTU, ceiling); |
280 | wind = (wind <= defaultThrottleRates.WindLimit) ? wind : defaultThrottleRates.WindLimit; | 305 | wind = Utils.Clamp(wind, Packet.MTU, ceiling); |
281 | cloud = (cloud <= defaultThrottleRates.CloudLimit) ? cloud : defaultThrottleRates.CloudLimit; | 306 | cloud = Utils.Clamp(cloud, Packet.MTU, ceiling); |
282 | task = (task <= defaultThrottleRates.TaskLimit) ? task : defaultThrottleRates.TaskLimit; | 307 | task = Utils.Clamp(task, Packet.MTU, ceiling); |
283 | texture = (texture <= defaultThrottleRates.TextureLimit) ? texture : defaultThrottleRates.TextureLimit; | 308 | texture = Utils.Clamp(texture, Packet.MTU, ceiling); |
284 | asset = (asset <= defaultThrottleRates.AssetLimit) ? asset : defaultThrottleRates.AssetLimit; | 309 | asset = Utils.Clamp(asset, Packet.MTU, ceiling); |
285 | 310 | state = Utils.Clamp(state, Packet.MTU, ceiling); | |
286 | SetThrottle(ThrottleOutPacketType.Resend, resend); | 311 | |
287 | SetThrottle(ThrottleOutPacketType.Land, land); | 312 | int total = resend + land + wind + cloud + task + texture + asset + state; |
288 | SetThrottle(ThrottleOutPacketType.Wind, wind); | 313 | int taskTotal = task + state; |
289 | SetThrottle(ThrottleOutPacketType.Cloud, cloud); | 314 | |
290 | SetThrottle(ThrottleOutPacketType.Task, task); | 315 | m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, State={8}, Total={9}", |
291 | SetThrottle(ThrottleOutPacketType.Texture, texture); | 316 | AgentID, resend, land, wind, cloud, task, texture, asset, state, total); |
292 | SetThrottle(ThrottleOutPacketType.Asset, asset); | 317 | |
318 | SetThrottle(ThrottleOutPacketType.Resend, resend, resend); | ||
319 | SetThrottle(ThrottleOutPacketType.Land, land, land); | ||
320 | SetThrottle(ThrottleOutPacketType.Wind, wind, wind); | ||
321 | SetThrottle(ThrottleOutPacketType.Cloud, cloud, cloud); | ||
322 | SetThrottle(ThrottleOutPacketType.Task, task, taskTotal); | ||
323 | SetThrottle(ThrottleOutPacketType.Texture, texture, texture); | ||
324 | SetThrottle(ThrottleOutPacketType.Asset, asset, asset); | ||
325 | SetThrottle(ThrottleOutPacketType.State, state, taskTotal); | ||
293 | } | 326 | } |
294 | 327 | ||
295 | public byte[] GetThrottlesPacked() | 328 | public byte[] GetThrottlesPacked() |
@@ -297,25 +330,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
297 | byte[] data = new byte[7 * 4]; | 330 | byte[] data = new byte[7 * 4]; |
298 | int i = 0; | 331 | int i = 0; |
299 | 332 | ||
300 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4; | 333 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4; |
301 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; | 334 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; |
302 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; | 335 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; |
303 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; | 336 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; |
304 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Task].DripRate), 0, data, i, 4); i += 4; | 337 | Buffer.BlockCopy(Utils.FloatToBytes((float)(m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) + |
305 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; | 338 | m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4; |
306 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; | 339 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; |
340 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; | ||
307 | 341 | ||
308 | return data; | 342 | return data; |
309 | } | 343 | } |
310 | 344 | ||
311 | public void SetThrottle(ThrottleOutPacketType category, int rate) | 345 | public void SetThrottle(ThrottleOutPacketType category, int rate, int maxBurst) |
312 | { | 346 | { |
313 | int i = (int)category; | 347 | int i = (int)category; |
314 | if (i >= 0 && i < throttleCategories.Length) | 348 | if (i >= 0 && i < m_throttleCategories.Length) |
315 | { | 349 | { |
316 | TokenBucket bucket = throttleCategories[(int)category]; | 350 | TokenBucket bucket = m_throttleCategories[(int)category]; |
317 | bucket.MaxBurst = rate; | ||
318 | bucket.DripRate = rate; | 351 | bucket.DripRate = rate; |
352 | bucket.MaxBurst = maxBurst; | ||
319 | } | 353 | } |
320 | } | 354 | } |
321 | 355 | ||
@@ -323,12 +357,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
323 | { | 357 | { |
324 | int category = (int)packet.Category; | 358 | int category = (int)packet.Category; |
325 | 359 | ||
326 | if (category >= 0 && category < packetOutboxes.Length) | 360 | if (category >= 0 && category < m_packetOutboxes.Length) |
327 | { | 361 | { |
328 | LocklessQueue<OutgoingPacket> queue = packetOutboxes[category]; | 362 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; |
329 | TokenBucket bucket = throttleCategories[category]; | 363 | TokenBucket bucket = m_throttleCategories[category]; |
330 | 364 | ||
331 | if (throttleCategories[category].RemoveTokens(packet.Buffer.DataLength)) | 365 | if (m_throttleCategories[category].RemoveTokens(packet.Buffer.DataLength)) |
332 | { | 366 | { |
333 | // Enough tokens were removed from the bucket, the packet will not be queued | 367 | // Enough tokens were removed from the bucket, the packet will not be queued |
334 | return false; | 368 | return false; |
@@ -357,24 +391,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
357 | public bool DequeueOutgoing() | 391 | public bool DequeueOutgoing() |
358 | { | 392 | { |
359 | OutgoingPacket packet; | 393 | OutgoingPacket packet; |
360 | LocklessQueue<OutgoingPacket> queue; | 394 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; |
361 | TokenBucket bucket; | 395 | TokenBucket bucket; |
362 | bool packetSent = false; | 396 | bool packetSent = false; |
363 | 397 | ||
364 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 398 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
365 | { | 399 | { |
366 | bucket = throttleCategories[i]; | 400 | bucket = m_throttleCategories[i]; |
367 | 401 | ||
368 | if (nextPackets[i] != null) | 402 | if (m_nextPackets[i] != null) |
369 | { | 403 | { |
370 | // This bucket was empty the last time we tried to send a packet, | 404 | // This bucket was empty the last time we tried to send a packet, |
371 | // leaving a dequeued packet still waiting to be sent out. Try to | 405 | // leaving a dequeued packet still waiting to be sent out. Try to |
372 | // send it again | 406 | // send it again |
373 | if (bucket.RemoveTokens(nextPacketLengths[i])) | 407 | OutgoingPacket nextPacket = m_nextPackets[i]; |
408 | if (bucket.RemoveTokens(nextPacket.Buffer.DataLength)) | ||
374 | { | 409 | { |
375 | // Send the packet | 410 | // Send the packet |
376 | udpServer.SendPacketFinal(nextPackets[i]); | 411 | m_udpServer.SendPacketFinal(nextPacket); |
377 | nextPackets[i] = null; | 412 | m_nextPackets[i] = null; |
378 | packetSent = true; | 413 | packetSent = true; |
379 | } | 414 | } |
380 | } | 415 | } |
@@ -382,7 +417,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
382 | { | 417 | { |
383 | // No dequeued packet waiting to be sent, try to pull one off | 418 | // No dequeued packet waiting to be sent, try to pull one off |
384 | // this queue | 419 | // this queue |
385 | queue = packetOutboxes[i]; | 420 | queue = m_packetOutboxes[i]; |
386 | if (queue.Dequeue(out packet)) | 421 | if (queue.Dequeue(out packet)) |
387 | { | 422 | { |
388 | // A packet was pulled off the queue. See if we have | 423 | // A packet was pulled off the queue. See if we have |
@@ -390,23 +425,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
390 | if (bucket.RemoveTokens(packet.Buffer.DataLength)) | 425 | if (bucket.RemoveTokens(packet.Buffer.DataLength)) |
391 | { | 426 | { |
392 | // Send the packet | 427 | // Send the packet |
393 | udpServer.SendPacketFinal(packet); | 428 | m_udpServer.SendPacketFinal(packet); |
394 | packetSent = true; | 429 | packetSent = true; |
395 | } | 430 | } |
396 | else | 431 | else |
397 | { | 432 | { |
398 | // Save the dequeued packet and the length calculation for | 433 | // Save the dequeued packet for the next iteration |
399 | // the next iteration | 434 | m_nextPackets[i] = packet; |
400 | nextPackets[i] = packet; | ||
401 | nextPacketLengths[i] = packet.Buffer.DataLength; | ||
402 | } | 435 | } |
436 | |||
437 | // If the queue is empty after this dequeue, fire the queue | ||
438 | // empty callback now so it has a chance to fill before we | ||
439 | // get back here | ||
440 | if (queue.Count == 0) | ||
441 | BeginFireQueueEmpty(i); | ||
403 | } | 442 | } |
404 | else | 443 | else |
405 | { | 444 | { |
406 | // No packets in this queue. Fire the queue empty callback | 445 | // No packets in this queue. Fire the queue empty callback |
407 | QueueEmpty callback = OnQueueEmpty; | 446 | // if it has not been called recently |
408 | if (callback != null) | 447 | BeginFireQueueEmpty(i); |
409 | callback((ThrottleOutPacketType)i); | ||
410 | } | 448 | } |
411 | } | 449 | } |
412 | } | 450 | } |
@@ -414,6 +452,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
414 | return packetSent; | 452 | return packetSent; |
415 | } | 453 | } |
416 | 454 | ||
455 | /// <summary> | ||
456 | /// Called when an ACK packet is received and a round-trip time for a | ||
457 | /// packet is calculated. This is used to calculate the smoothed | ||
458 | /// round-trip time, round trip time variance, and finally the | ||
459 | /// retransmission timeout | ||
460 | /// </summary> | ||
461 | /// <param name="r">Round-trip time of a single packet and its | ||
462 | /// acknowledgement</param> | ||
417 | public void UpdateRoundTrip(float r) | 463 | public void UpdateRoundTrip(float r) |
418 | { | 464 | { |
419 | const float ALPHA = 0.125f; | 465 | const float ALPHA = 0.125f; |
@@ -435,8 +481,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
435 | 481 | ||
436 | // Always round retransmission timeout up to two seconds | 482 | // Always round retransmission timeout up to two seconds |
437 | RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR))); | 483 | RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR))); |
438 | //Logger.Debug("Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + | 484 | //m_log.Debug("[LLUDPCLIENT]: Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + |
439 | // RTTVAR + " based on new RTT of " + r + "ms"); | 485 | // RTTVAR + " based on new RTT of " + r + "ms"); |
440 | } | 486 | } |
487 | |||
488 | /// <summary> | ||
489 | /// Does an early check to see if this queue empty callback is already | ||
490 | /// running, then asynchronously firing the event | ||
491 | /// </summary> | ||
492 | /// <param name="throttleIndex">Throttle category to fire the callback | ||
493 | /// for</param> | ||
494 | private void BeginFireQueueEmpty(int throttleIndex) | ||
495 | { | ||
496 | if (!m_onQueueEmptyRunning[throttleIndex]) | ||
497 | Util.FireAndForget(FireQueueEmpty, throttleIndex); | ||
498 | } | ||
499 | |||
500 | /// <summary> | ||
501 | /// Checks to see if this queue empty callback is already running, | ||
502 | /// then firing the event | ||
503 | /// </summary> | ||
504 | /// <param name="o">Throttle category to fire the callback for, stored | ||
505 | /// as an object to match the WaitCallback delegate signature</param> | ||
506 | private void FireQueueEmpty(object o) | ||
507 | { | ||
508 | int i = (int)o; | ||
509 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; | ||
510 | QueueEmpty callback = OnQueueEmpty; | ||
511 | |||
512 | if (callback != null) | ||
513 | { | ||
514 | if (!m_onQueueEmptyRunning[i]) | ||
515 | { | ||
516 | m_onQueueEmptyRunning[i] = true; | ||
517 | try { callback(type); } | ||
518 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); } | ||
519 | m_onQueueEmptyRunning[i] = false; | ||
520 | } | ||
521 | } | ||
522 | } | ||
441 | } | 523 | } |
442 | } | 524 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs deleted file mode 100644 index dbb9861..0000000 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs +++ /dev/null | |||
@@ -1,282 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
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 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Net; | ||
31 | using OpenSim.Framework; | ||
32 | using OpenMetaverse; | ||
33 | |||
34 | using ReaderWriterLockImpl = OpenMetaverse.ReaderWriterLockSlim; | ||
35 | |||
36 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
37 | { | ||
38 | public sealed class UDPClientCollection | ||
39 | { | ||
40 | Dictionary<UUID, LLUDPClient> Dictionary1; | ||
41 | Dictionary<IPEndPoint, LLUDPClient> Dictionary2; | ||
42 | LLUDPClient[] Array; | ||
43 | ReaderWriterLockImpl rwLock = new ReaderWriterLockImpl(); | ||
44 | object m_sync = new object(); | ||
45 | |||
46 | public UDPClientCollection() | ||
47 | { | ||
48 | Dictionary1 = new Dictionary<UUID, LLUDPClient>(); | ||
49 | Dictionary2 = new Dictionary<IPEndPoint, LLUDPClient>(); | ||
50 | Array = new LLUDPClient[0]; | ||
51 | } | ||
52 | |||
53 | public UDPClientCollection(int capacity) | ||
54 | { | ||
55 | Dictionary1 = new Dictionary<UUID, LLUDPClient>(capacity); | ||
56 | Dictionary2 = new Dictionary<IPEndPoint, LLUDPClient>(capacity); | ||
57 | Array = new LLUDPClient[0]; | ||
58 | } | ||
59 | |||
60 | public void Add(UUID key1, IPEndPoint key2, LLUDPClient value) | ||
61 | { | ||
62 | //rwLock.EnterWriteLock(); | ||
63 | |||
64 | //try | ||
65 | //{ | ||
66 | // if (Dictionary1.ContainsKey(key1)) | ||
67 | // { | ||
68 | // if (!Dictionary2.ContainsKey(key2)) | ||
69 | // throw new ArgumentException("key1 exists in the dictionary but not key2"); | ||
70 | // } | ||
71 | // else if (Dictionary2.ContainsKey(key2)) | ||
72 | // { | ||
73 | // if (!Dictionary1.ContainsKey(key1)) | ||
74 | // throw new ArgumentException("key2 exists in the dictionary but not key1"); | ||
75 | // } | ||
76 | |||
77 | // Dictionary1[key1] = value; | ||
78 | // Dictionary2[key2] = value; | ||
79 | |||
80 | // LLUDPClient[] oldArray = Array; | ||
81 | // int oldLength = oldArray.Length; | ||
82 | |||
83 | // LLUDPClient[] newArray = new LLUDPClient[oldLength + 1]; | ||
84 | // for (int i = 0; i < oldLength; i++) | ||
85 | // newArray[i] = oldArray[i]; | ||
86 | // newArray[oldLength] = value; | ||
87 | |||
88 | // Array = newArray; | ||
89 | //} | ||
90 | //finally { rwLock.ExitWriteLock(); } | ||
91 | |||
92 | lock (m_sync) | ||
93 | { | ||
94 | if (Dictionary1.ContainsKey(key1)) | ||
95 | { | ||
96 | if (!Dictionary2.ContainsKey(key2)) | ||
97 | throw new ArgumentException("key1 exists in the dictionary but not key2"); | ||
98 | } | ||
99 | else if (Dictionary2.ContainsKey(key2)) | ||
100 | { | ||
101 | if (!Dictionary1.ContainsKey(key1)) | ||
102 | throw new ArgumentException("key2 exists in the dictionary but not key1"); | ||
103 | } | ||
104 | |||
105 | Dictionary1[key1] = value; | ||
106 | Dictionary2[key2] = value; | ||
107 | |||
108 | LLUDPClient[] oldArray = Array; | ||
109 | int oldLength = oldArray.Length; | ||
110 | |||
111 | LLUDPClient[] newArray = new LLUDPClient[oldLength + 1]; | ||
112 | for (int i = 0; i < oldLength; i++) | ||
113 | newArray[i] = oldArray[i]; | ||
114 | newArray[oldLength] = value; | ||
115 | |||
116 | Array = newArray; | ||
117 | } | ||
118 | |||
119 | } | ||
120 | |||
121 | public bool Remove(UUID key1, IPEndPoint key2) | ||
122 | { | ||
123 | //rwLock.EnterWriteLock(); | ||
124 | |||
125 | //try | ||
126 | //{ | ||
127 | // LLUDPClient value; | ||
128 | // if (Dictionary1.TryGetValue(key1, out value)) | ||
129 | // { | ||
130 | // Dictionary1.Remove(key1); | ||
131 | // Dictionary2.Remove(key2); | ||
132 | |||
133 | // LLUDPClient[] oldArray = Array; | ||
134 | // int oldLength = oldArray.Length; | ||
135 | |||
136 | // LLUDPClient[] newArray = new LLUDPClient[oldLength - 1]; | ||
137 | // int j = 0; | ||
138 | // for (int i = 0; i < oldLength; i++) | ||
139 | // { | ||
140 | // if (oldArray[i] != value) | ||
141 | // newArray[j++] = oldArray[i]; | ||
142 | // } | ||
143 | |||
144 | // Array = newArray; | ||
145 | // return true; | ||
146 | // } | ||
147 | //} | ||
148 | //finally { rwLock.ExitWriteLock(); } | ||
149 | |||
150 | //return false; | ||
151 | |||
152 | lock (m_sync) | ||
153 | { | ||
154 | LLUDPClient value; | ||
155 | if (Dictionary1.TryGetValue(key1, out value)) | ||
156 | { | ||
157 | Dictionary1.Remove(key1); | ||
158 | Dictionary2.Remove(key2); | ||
159 | |||
160 | LLUDPClient[] oldArray = Array; | ||
161 | int oldLength = oldArray.Length; | ||
162 | |||
163 | LLUDPClient[] newArray = new LLUDPClient[oldLength - 1]; | ||
164 | int j = 0; | ||
165 | for (int i = 0; i < oldLength; i++) | ||
166 | { | ||
167 | if (oldArray[i] != value) | ||
168 | newArray[j++] = oldArray[i]; | ||
169 | } | ||
170 | |||
171 | Array = newArray; | ||
172 | return true; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | return false; | ||
177 | |||
178 | } | ||
179 | |||
180 | public void Clear() | ||
181 | { | ||
182 | //rwLock.EnterWriteLock(); | ||
183 | |||
184 | //try | ||
185 | //{ | ||
186 | // Dictionary1.Clear(); | ||
187 | // Dictionary2.Clear(); | ||
188 | // Array = new LLUDPClient[0]; | ||
189 | //} | ||
190 | //finally { rwLock.ExitWriteLock(); } | ||
191 | |||
192 | lock (m_sync) | ||
193 | { | ||
194 | Dictionary1.Clear(); | ||
195 | Dictionary2.Clear(); | ||
196 | Array = new LLUDPClient[0]; | ||
197 | } | ||
198 | |||
199 | } | ||
200 | |||
201 | public int Count | ||
202 | { | ||
203 | get { return Array.Length; } | ||
204 | } | ||
205 | |||
206 | public bool ContainsKey(UUID key) | ||
207 | { | ||
208 | return Dictionary1.ContainsKey(key); | ||
209 | } | ||
210 | |||
211 | public bool ContainsKey(IPEndPoint key) | ||
212 | { | ||
213 | return Dictionary2.ContainsKey(key); | ||
214 | } | ||
215 | |||
216 | public bool TryGetValue(UUID key, out LLUDPClient value) | ||
217 | { | ||
218 | ////bool success; | ||
219 | ////bool doLock = !rwLock.IsUpgradeableReadLockHeld; | ||
220 | ////if (doLock) rwLock.EnterReadLock(); | ||
221 | |||
222 | ////try { success = Dictionary1.TryGetValue(key, out value); } | ||
223 | ////finally { if (doLock) rwLock.ExitReadLock(); } | ||
224 | |||
225 | ////return success; | ||
226 | |||
227 | lock (m_sync) | ||
228 | return Dictionary1.TryGetValue(key, out value); | ||
229 | |||
230 | //try | ||
231 | //{ | ||
232 | // return Dictionary1.TryGetValue(key, out value); | ||
233 | //} | ||
234 | //catch { } | ||
235 | //value = null; | ||
236 | //return false; | ||
237 | } | ||
238 | |||
239 | public bool TryGetValue(IPEndPoint key, out LLUDPClient value) | ||
240 | { | ||
241 | ////bool success; | ||
242 | ////bool doLock = !rwLock.IsUpgradeableReadLockHeld; | ||
243 | ////if (doLock) rwLock.EnterReadLock(); | ||
244 | |||
245 | ////try { success = Dictionary2.TryGetValue(key, out value); } | ||
246 | ////finally { if (doLock) rwLock.ExitReadLock(); } | ||
247 | |||
248 | ////return success; | ||
249 | |||
250 | lock (m_sync) | ||
251 | return Dictionary2.TryGetValue(key, out value); | ||
252 | |||
253 | //try | ||
254 | //{ | ||
255 | // return Dictionary2.TryGetValue(key, out value); | ||
256 | //} | ||
257 | //catch { } | ||
258 | //value = null; | ||
259 | //return false; | ||
260 | |||
261 | } | ||
262 | |||
263 | public void ForEach(Action<LLUDPClient> action) | ||
264 | { | ||
265 | //bool doLock = !rwLock.IsUpgradeableReadLockHeld; | ||
266 | //if (doLock) rwLock.EnterUpgradeableReadLock(); | ||
267 | |||
268 | //try { Parallel.ForEach<LLUDPClient>(Array, action); } | ||
269 | //finally { if (doLock) rwLock.ExitUpgradeableReadLock(); } | ||
270 | |||
271 | LLUDPClient[] localArray = null; | ||
272 | lock (m_sync) | ||
273 | { | ||
274 | localArray = new LLUDPClient[Array.Length]; | ||
275 | Array.CopyTo(localArray, 0); | ||
276 | } | ||
277 | |||
278 | Parallel.ForEach<LLUDPClient>(localArray, action); | ||
279 | |||
280 | } | ||
281 | } | ||
282 | } | ||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index c356f02..890f701 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | |||
@@ -96,7 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
96 | /// <summary>Incoming packets that are awaiting handling</summary> | 96 | /// <summary>Incoming packets that are awaiting handling</summary> |
97 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); | 97 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); |
98 | /// <summary></summary> | 98 | /// <summary></summary> |
99 | private UDPClientCollection clients = new UDPClientCollection(); | 99 | //private UDPClientCollection m_clients = new UDPClientCollection(); |
100 | /// <summary>Bandwidth throttle for this UDP server</summary> | 100 | /// <summary>Bandwidth throttle for this UDP server</summary> |
101 | private TokenBucket m_throttle; | 101 | private TokenBucket m_throttle; |
102 | /// <summary>Bandwidth throttle rates for this UDP server</summary> | 102 | /// <summary>Bandwidth throttle rates for this UDP server</summary> |
@@ -109,13 +109,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
109 | private Location m_location; | 109 | private Location m_location; |
110 | /// <summary>The measured resolution of Environment.TickCount</summary> | 110 | /// <summary>The measured resolution of Environment.TickCount</summary> |
111 | private float m_tickCountResolution; | 111 | private float m_tickCountResolution; |
112 | /// <summary>The size of the receive buffer for the UDP socket. This value | ||
113 | /// is passed up to the operating system and used in the system networking | ||
114 | /// stack. Use zero to leave this value as the default</summary> | ||
115 | private int m_recvBufferSize; | ||
112 | 116 | ||
113 | /// <summary>The measured resolution of Environment.TickCount</summary> | 117 | /// <summary>The measured resolution of Environment.TickCount</summary> |
114 | public float TickCountResolution { get { return m_tickCountResolution; } } | 118 | public float TickCountResolution { get { return m_tickCountResolution; } } |
115 | public Socket Server { get { return null; } } | 119 | public Socket Server { get { return null; } } |
116 | 120 | ||
117 | public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) | 121 | public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) |
118 | : base((int)port) | 122 | : base(listenIP, (int)port) |
119 | { | 123 | { |
120 | #region Environment.TickCount Measurement | 124 | #region Environment.TickCount Measurement |
121 | 125 | ||
@@ -134,18 +138,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
134 | #endregion Environment.TickCount Measurement | 138 | #endregion Environment.TickCount Measurement |
135 | 139 | ||
136 | m_circuitManager = circuitManager; | 140 | m_circuitManager = circuitManager; |
141 | int sceneThrottleBps = 0; | ||
137 | 142 | ||
138 | // TODO: Config support for throttling the entire connection | 143 | IConfig config = configSource.Configs["ClientStack.LindenUDP"]; |
139 | m_throttle = new TokenBucket(null, 0, 0); | 144 | if (config != null) |
145 | { | ||
146 | m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0); | ||
147 | sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0); | ||
148 | } | ||
149 | |||
150 | m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps); | ||
140 | m_throttleRates = new ThrottleRates(configSource); | 151 | m_throttleRates = new ThrottleRates(configSource); |
141 | } | 152 | } |
142 | 153 | ||
143 | public new void Start() | 154 | public void Start() |
144 | { | 155 | { |
145 | if (m_scene == null) | 156 | if (m_scene == null) |
146 | throw new InvalidOperationException("Cannot LLUDPServer.Start() without an IScene reference"); | 157 | throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); |
147 | 158 | ||
148 | base.Start(); | 159 | base.Start(m_recvBufferSize); |
149 | 160 | ||
150 | // Start the incoming packet processing thread | 161 | // Start the incoming packet processing thread |
151 | Thread incomingThread = new Thread(IncomingPacketHandler); | 162 | Thread incomingThread = new Thread(IncomingPacketHandler); |
@@ -181,24 +192,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
181 | return x == m_location; | 192 | return x == m_location; |
182 | } | 193 | } |
183 | 194 | ||
184 | public void RemoveClient(IClientAPI client) | ||
185 | { | ||
186 | m_scene.ClientManager.Remove(client.CircuitCode); | ||
187 | client.Close(false); | ||
188 | |||
189 | LLUDPClient udpClient; | ||
190 | if (clients.TryGetValue(client.AgentId, out udpClient)) | ||
191 | { | ||
192 | m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + client.Name + " in " + m_scene.RegionInfo.RegionName); | ||
193 | udpClient.Shutdown(); | ||
194 | clients.Remove(client.AgentId, udpClient.RemoteEndPoint); | ||
195 | } | ||
196 | else | ||
197 | { | ||
198 | m_log.Warn("[LLUDPSERVER]: Failed to remove LLUDPClient for " + client.Name); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) | 195 | public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) |
203 | { | 196 | { |
204 | // CoarseLocationUpdate packets cannot be split in an automated way | 197 | // CoarseLocationUpdate packets cannot be split in an automated way |
@@ -216,30 +209,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
216 | for (int i = 0; i < packetCount; i++) | 209 | for (int i = 0; i < packetCount; i++) |
217 | { | 210 | { |
218 | byte[] data = datas[i]; | 211 | byte[] data = datas[i]; |
219 | clients.ForEach( | 212 | m_scene.ClientManager.ForEach( |
220 | delegate(LLUDPClient client) | 213 | delegate(IClientAPI client) |
221 | { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); | 214 | { |
215 | if (client is LLClientView) | ||
216 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category); | ||
217 | } | ||
218 | ); | ||
222 | } | 219 | } |
223 | } | 220 | } |
224 | else | 221 | else |
225 | { | 222 | { |
226 | byte[] data = packet.ToBytes(); | 223 | byte[] data = packet.ToBytes(); |
227 | clients.ForEach( | 224 | m_scene.ClientManager.ForEach( |
228 | delegate(LLUDPClient client) | 225 | delegate(IClientAPI client) |
229 | { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); | 226 | { |
227 | if (client is LLClientView) | ||
228 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category); | ||
229 | } | ||
230 | ); | ||
230 | } | 231 | } |
231 | } | 232 | } |
232 | 233 | ||
233 | public void SendPacket(UUID agentID, Packet packet, ThrottleOutPacketType category, bool allowSplitting) | 234 | public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting) |
234 | { | ||
235 | LLUDPClient client; | ||
236 | if (clients.TryGetValue(agentID, out client)) | ||
237 | SendPacket(client, packet, category, allowSplitting); | ||
238 | else | ||
239 | m_log.Warn("[LLUDPSERVER]: Attempted to send a packet to unknown agentID " + agentID); | ||
240 | } | ||
241 | |||
242 | public void SendPacket(LLUDPClient client, Packet packet, ThrottleOutPacketType category, bool allowSplitting) | ||
243 | { | 235 | { |
244 | // CoarseLocationUpdate packets cannot be split in an automated way | 236 | // CoarseLocationUpdate packets cannot be split in an automated way |
245 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) | 237 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) |
@@ -256,25 +248,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
256 | for (int i = 0; i < packetCount; i++) | 248 | for (int i = 0; i < packetCount; i++) |
257 | { | 249 | { |
258 | byte[] data = datas[i]; | 250 | byte[] data = datas[i]; |
259 | SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); | 251 | SendPacketData(udpClient, data, packet.Type, category); |
260 | } | 252 | } |
261 | } | 253 | } |
262 | else | 254 | else |
263 | { | 255 | { |
264 | byte[] data = packet.ToBytes(); | 256 | byte[] data = packet.ToBytes(); |
265 | SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); | 257 | SendPacketData(udpClient, data, packet.Type, category); |
266 | } | 258 | } |
267 | } | 259 | } |
268 | 260 | ||
269 | public void SendPacketData(LLUDPClient client, byte[] data, int dataLength, PacketType type, bool doZerocode, ThrottleOutPacketType category) | 261 | public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category) |
270 | { | 262 | { |
263 | int dataLength = data.Length; | ||
264 | bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; | ||
265 | |||
271 | // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. | 266 | // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. |
272 | // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting | 267 | // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting |
273 | // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here | 268 | // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here |
274 | // to accomodate for both common scenarios and provide ample room for ACK appending in both | 269 | // to accomodate for both common scenarios and provide ample room for ACK appending in both |
275 | int bufferSize = (dataLength > 180) ? Packet.MTU : 200; | 270 | int bufferSize = (dataLength > 180) ? Packet.MTU : 200; |
276 | 271 | ||
277 | UDPPacketBuffer buffer = new UDPPacketBuffer(client.RemoteEndPoint, bufferSize); | 272 | UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); |
278 | 273 | ||
279 | // Zerocode if needed | 274 | // Zerocode if needed |
280 | if (doZerocode) | 275 | if (doZerocode) |
@@ -285,17 +280,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
285 | // The packet grew larger than the bufferSize while zerocoding. | 280 | // The packet grew larger than the bufferSize while zerocoding. |
286 | // Remove the MSG_ZEROCODED flag and send the unencoded data | 281 | // Remove the MSG_ZEROCODED flag and send the unencoded data |
287 | // instead | 282 | // instead |
288 | m_log.Info("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding. Removing MSG_ZEROCODED flag"); | 283 | m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". Removing MSG_ZEROCODED flag"); |
289 | data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); | 284 | data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); |
290 | // | ||
291 | buffer = new UDPPacketBuffer(client.RemoteEndPoint, dataLength); | ||
292 | // | ||
293 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | 285 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); |
294 | } | 286 | } |
295 | } | 287 | } |
296 | else | 288 | else |
297 | { | 289 | { |
298 | // ??? will it fit? | ||
299 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | 290 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); |
300 | } | 291 | } |
301 | buffer.DataLength = dataLength; | 292 | buffer.DataLength = dataLength; |
@@ -303,7 +294,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
303 | #region Queue or Send | 294 | #region Queue or Send |
304 | 295 | ||
305 | // Look up the UDPClient this is going to | 296 | // Look up the UDPClient this is going to |
306 | OutgoingPacket outgoingPacket = new OutgoingPacket(client, buffer, category); | 297 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); |
307 | 298 | ||
308 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) | 299 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) |
309 | SendPacketFinal(outgoingPacket); | 300 | SendPacketFinal(outgoingPacket); |
@@ -311,18 +302,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
311 | #endregion Queue or Send | 302 | #endregion Queue or Send |
312 | } | 303 | } |
313 | 304 | ||
314 | public void SendAcks(LLUDPClient client) | 305 | public void SendAcks(LLUDPClient udpClient) |
315 | { | 306 | { |
316 | uint ack; | 307 | uint ack; |
317 | 308 | ||
318 | if (client.PendingAcks.Dequeue(out ack)) | 309 | if (udpClient.PendingAcks.Dequeue(out ack)) |
319 | { | 310 | { |
320 | List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>(); | 311 | List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>(); |
321 | PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); | 312 | PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); |
322 | block.ID = ack; | 313 | block.ID = ack; |
323 | blocks.Add(block); | 314 | blocks.Add(block); |
324 | 315 | ||
325 | while (client.PendingAcks.Dequeue(out ack)) | 316 | while (udpClient.PendingAcks.Dequeue(out ack)) |
326 | { | 317 | { |
327 | block = new PacketAckPacket.PacketsBlock(); | 318 | block = new PacketAckPacket.PacketsBlock(); |
328 | block.ID = ack; | 319 | block.ID = ack; |
@@ -333,22 +324,39 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
333 | packet.Header.Reliable = false; | 324 | packet.Header.Reliable = false; |
334 | packet.Packets = blocks.ToArray(); | 325 | packet.Packets = blocks.ToArray(); |
335 | 326 | ||
336 | SendPacket(client, packet, ThrottleOutPacketType.Unknown, true); | 327 | SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true); |
337 | } | 328 | } |
338 | } | 329 | } |
339 | 330 | ||
340 | public void SendPing(LLUDPClient client) | 331 | public void SendPing(LLUDPClient udpClient) |
341 | { | 332 | { |
342 | IClientAPI api = client.ClientAPI; | 333 | StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); |
343 | if (api != null) | 334 | pc.Header.Reliable = false; |
344 | api.SendStartPingCheck(client.CurrentPingSequence++); | 335 | |
336 | OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest(); | ||
337 | |||
338 | pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++; | ||
339 | pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0; | ||
340 | |||
341 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); | ||
345 | } | 342 | } |
346 | 343 | ||
347 | public void ResendUnacked(LLUDPClient client) | 344 | public void ResendUnacked(LLUDPClient udpClient) |
348 | { | 345 | { |
349 | if (client.NeedAcks.Count > 0) | 346 | if (udpClient.IsConnected && udpClient.NeedAcks.Count > 0) |
350 | { | 347 | { |
351 | List<OutgoingPacket> expiredPackets = client.NeedAcks.GetExpiredPackets(client.RTO); | 348 | // Disconnect an agent if no packets are received for some time |
349 | //FIXME: Make 60 an .ini setting | ||
350 | if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60) | ||
351 | { | ||
352 | m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); | ||
353 | |||
354 | RemoveClient(udpClient); | ||
355 | return; | ||
356 | } | ||
357 | |||
358 | // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO | ||
359 | List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); | ||
352 | 360 | ||
353 | if (expiredPackets != null) | 361 | if (expiredPackets != null) |
354 | { | 362 | { |
@@ -357,54 +365,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
357 | { | 365 | { |
358 | OutgoingPacket outgoingPacket = expiredPackets[i]; | 366 | OutgoingPacket outgoingPacket = expiredPackets[i]; |
359 | 367 | ||
360 | // FIXME: Make this an .ini setting | 368 | //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed", |
361 | if (outgoingPacket.ResendCount < 3) | 369 | // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount); |
362 | { | ||
363 | //Logger.Debug(String.Format("Resending packet #{0} (attempt {1}), {2}ms have passed", | ||
364 | // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount)); | ||
365 | |||
366 | // Set the resent flag | ||
367 | outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); | ||
368 | outgoingPacket.Category = ThrottleOutPacketType.Resend; | ||
369 | 370 | ||
370 | // The TickCount will be set to the current time when the packet | 371 | // Set the resent flag |
371 | // is actually sent out again | 372 | outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); |
372 | outgoingPacket.TickCount = 0; | 373 | outgoingPacket.Category = ThrottleOutPacketType.Resend; |
373 | 374 | ||
374 | // Bump up the resend count on this packet | 375 | // The TickCount will be set to the current time when the packet |
375 | Interlocked.Increment(ref outgoingPacket.ResendCount); | 376 | // is actually sent out again |
376 | //Interlocked.Increment(ref Stats.ResentPackets); | 377 | outgoingPacket.TickCount = 0; |
377 | 378 | ||
378 | // Queue or (re)send the packet | 379 | // Bump up the resend count on this packet |
379 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) | 380 | Interlocked.Increment(ref outgoingPacket.ResendCount); |
380 | SendPacketFinal(outgoingPacket); | 381 | //Interlocked.Increment(ref Stats.ResentPackets); |
381 | } | ||
382 | else | ||
383 | { | ||
384 | m_log.DebugFormat("[LLUDPSERVER]: Dropping packet #{0} for agent {1} after {2} failed attempts", | ||
385 | outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount); | ||
386 | 382 | ||
387 | lock (client.NeedAcks.SyncRoot) | 383 | // Requeue or resend the packet |
388 | client.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber); | 384 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) |
389 | 385 | SendPacketFinal(outgoingPacket); | |
390 | //Interlocked.Increment(ref Stats.DroppedPackets); | ||
391 | |||
392 | // Disconnect an agent if no packets are received for some time | ||
393 | //FIXME: Make 60 an .ini setting | ||
394 | if (Environment.TickCount - client.TickLastPacketReceived > 1000 * 60) | ||
395 | { | ||
396 | m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + client.ClientAPI.Name); | ||
397 | |||
398 | RemoveClient(client.ClientAPI); | ||
399 | return; | ||
400 | } | ||
401 | } | ||
402 | } | 386 | } |
403 | } | 387 | } |
404 | } | 388 | } |
405 | } | 389 | } |
406 | 390 | ||
407 | public void Flush() | 391 | public void Flush(LLUDPClient udpClient) |
408 | { | 392 | { |
409 | // FIXME: Implement? | 393 | // FIXME: Implement? |
410 | } | 394 | } |
@@ -415,7 +399,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
415 | byte flags = buffer.Data[0]; | 399 | byte flags = buffer.Data[0]; |
416 | bool isResend = (flags & Helpers.MSG_RESENT) != 0; | 400 | bool isResend = (flags & Helpers.MSG_RESENT) != 0; |
417 | bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; | 401 | bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; |
418 | LLUDPClient client = outgoingPacket.Client; | 402 | LLUDPClient udpClient = outgoingPacket.Client; |
403 | |||
404 | if (!udpClient.IsConnected) | ||
405 | return; | ||
419 | 406 | ||
420 | // Keep track of when this packet was sent out (right now) | 407 | // Keep track of when this packet was sent out (right now) |
421 | outgoingPacket.TickCount = Environment.TickCount; | 408 | outgoingPacket.TickCount = Environment.TickCount; |
@@ -424,11 +411,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
424 | 411 | ||
425 | int dataLength = buffer.DataLength; | 412 | int dataLength = buffer.DataLength; |
426 | 413 | ||
427 | // Keep appending ACKs until there is no room left in the packet or there are | 414 | // Keep appending ACKs until there is no room left in the buffer or there are |
428 | // no more ACKs to append | 415 | // no more ACKs to append |
429 | uint ackCount = 0; | 416 | uint ackCount = 0; |
430 | uint ack; | 417 | uint ack; |
431 | while (dataLength + 5 < buffer.Data.Length && client.PendingAcks.Dequeue(out ack)) | 418 | while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack)) |
432 | { | 419 | { |
433 | Utils.UIntToBytesBig(ack, buffer.Data, dataLength); | 420 | Utils.UIntToBytesBig(ack, buffer.Data, dataLength); |
434 | dataLength += 4; | 421 | dataLength += 4; |
@@ -447,24 +434,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
447 | 434 | ||
448 | #endregion ACK Appending | 435 | #endregion ACK Appending |
449 | 436 | ||
437 | #region Sequence Number Assignment | ||
438 | |||
450 | if (!isResend) | 439 | if (!isResend) |
451 | { | 440 | { |
452 | // Not a resend, assign a new sequence number | 441 | // Not a resend, assign a new sequence number |
453 | uint sequenceNumber = (uint)Interlocked.Increment(ref client.CurrentSequence); | 442 | uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence); |
454 | Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); | 443 | Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); |
455 | outgoingPacket.SequenceNumber = sequenceNumber; | 444 | outgoingPacket.SequenceNumber = sequenceNumber; |
456 | 445 | ||
457 | if (isReliable) | 446 | if (isReliable) |
458 | { | 447 | { |
459 | // Add this packet to the list of ACK responses we are waiting on from the server | 448 | // Add this packet to the list of ACK responses we are waiting on from the server |
460 | client.NeedAcks.Add(outgoingPacket); | 449 | udpClient.NeedAcks.Add(outgoingPacket); |
461 | } | 450 | } |
462 | } | 451 | } |
463 | 452 | ||
453 | #endregion Sequence Number Assignment | ||
454 | |||
464 | // Stats tracking | 455 | // Stats tracking |
465 | Interlocked.Increment(ref client.PacketsSent); | 456 | Interlocked.Increment(ref udpClient.PacketsSent); |
466 | if (isReliable) | 457 | if (isReliable) |
467 | Interlocked.Add(ref client.UnackedBytes, outgoingPacket.Buffer.DataLength); | 458 | Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength); |
468 | 459 | ||
469 | // Put the UDP payload on the wire | 460 | // Put the UDP payload on the wire |
470 | AsyncBeginSend(buffer); | 461 | AsyncBeginSend(buffer); |
@@ -473,10 +464,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
473 | protected override void PacketReceived(UDPPacketBuffer buffer) | 464 | protected override void PacketReceived(UDPPacketBuffer buffer) |
474 | { | 465 | { |
475 | // Debugging/Profiling | 466 | // Debugging/Profiling |
476 | //try { Thread.CurrentThread.Name = "PacketReceived (" + scene.RegionName + ")"; } | 467 | //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; } |
477 | //catch (Exception) { } | 468 | //catch (Exception) { } |
478 | 469 | ||
479 | LLUDPClient client = null; | 470 | LLUDPClient udpClient = null; |
480 | Packet packet = null; | 471 | Packet packet = null; |
481 | int packetEnd = buffer.DataLength - 1; | 472 | int packetEnd = buffer.DataLength - 1; |
482 | IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; | 473 | IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; |
@@ -491,61 +482,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
491 | } | 482 | } |
492 | catch (MalformedDataException) | 483 | catch (MalformedDataException) |
493 | { | 484 | { |
494 | m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet:\n{0}", | 485 | m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet from {0}:\n{1}", |
495 | Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | 486 | buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); |
496 | } | 487 | } |
497 | 488 | ||
498 | // Fail-safe check | 489 | // Fail-safe check |
499 | if (packet == null) | 490 | if (packet == null) |
500 | { | 491 | { |
501 | m_log.Warn("[LLUDPSERVER]: Couldn't build a message from the incoming data"); | 492 | m_log.Warn("[LLUDPSERVER]: Couldn't build a message from incoming data " + buffer.DataLength + |
493 | " bytes long from " + buffer.RemoteEndPoint); | ||
502 | return; | 494 | return; |
503 | } | 495 | } |
504 | 496 | ||
505 | //Stats.RecvBytes += (ulong)buffer.DataLength; | ||
506 | //++Stats.RecvPackets; | ||
507 | |||
508 | #endregion Decoding | 497 | #endregion Decoding |
509 | 498 | ||
510 | #region UseCircuitCode Handling | 499 | #region Packet to Client Mapping |
511 | 500 | ||
501 | // UseCircuitCode handling | ||
512 | if (packet.Type == PacketType.UseCircuitCode) | 502 | if (packet.Type == PacketType.UseCircuitCode) |
513 | { | 503 | { |
514 | UseCircuitCodePacket useCircuitCode = (UseCircuitCodePacket)packet; | 504 | AddNewClient((UseCircuitCodePacket)packet, (IPEndPoint)buffer.RemoteEndPoint); |
515 | IClientAPI newuser; | ||
516 | uint circuitCode = useCircuitCode.CircuitCode.Code; | ||
517 | |||
518 | // Check if the client is already established | ||
519 | if (!m_scene.ClientManager.TryGetClient(circuitCode, out newuser)) | ||
520 | { | ||
521 | AddNewClient(useCircuitCode, (IPEndPoint)buffer.RemoteEndPoint); | ||
522 | } | ||
523 | } | 505 | } |
524 | 506 | ||
525 | // Determine which agent this packet came from | 507 | // Determine which agent this packet came from |
526 | if (!clients.TryGetValue(address, out client)) | 508 | IClientAPI client; |
509 | if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView)) | ||
527 | { | 510 | { |
528 | m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 511 | m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + |
512 | " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients"); | ||
529 | return; | 513 | return; |
530 | } | 514 | } |
531 | 515 | ||
532 | #endregion UseCircuitCode Handling | 516 | udpClient = ((LLClientView)client).UDPClient; |
517 | |||
518 | if (!udpClient.IsConnected) | ||
519 | return; | ||
520 | |||
521 | #endregion Packet to Client Mapping | ||
533 | 522 | ||
534 | // Stats tracking | 523 | // Stats tracking |
535 | Interlocked.Increment(ref client.PacketsReceived); | 524 | Interlocked.Increment(ref udpClient.PacketsReceived); |
536 | 525 | ||
537 | #region ACK Receiving | 526 | #region ACK Receiving |
538 | 527 | ||
539 | int now = Environment.TickCount; | 528 | int now = Environment.TickCount; |
540 | client.TickLastPacketReceived = now; | 529 | udpClient.TickLastPacketReceived = now; |
541 | 530 | ||
542 | // Handle appended ACKs | 531 | // Handle appended ACKs |
543 | if (packet.Header.AppendedAcks && packet.Header.AckList != null) | 532 | if (packet.Header.AppendedAcks && packet.Header.AckList != null) |
544 | { | 533 | { |
545 | lock (client.NeedAcks.SyncRoot) | 534 | lock (udpClient.NeedAcks.SyncRoot) |
546 | { | 535 | { |
547 | for (int i = 0; i < packet.Header.AckList.Length; i++) | 536 | for (int i = 0; i < packet.Header.AckList.Length; i++) |
548 | AcknowledgePacket(client, packet.Header.AckList[i], now, packet.Header.Resent); | 537 | AcknowledgePacket(udpClient, packet.Header.AckList[i], now, packet.Header.Resent); |
549 | } | 538 | } |
550 | } | 539 | } |
551 | 540 | ||
@@ -554,10 +543,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
554 | { | 543 | { |
555 | PacketAckPacket ackPacket = (PacketAckPacket)packet; | 544 | PacketAckPacket ackPacket = (PacketAckPacket)packet; |
556 | 545 | ||
557 | lock (client.NeedAcks.SyncRoot) | 546 | lock (udpClient.NeedAcks.SyncRoot) |
558 | { | 547 | { |
559 | for (int i = 0; i < ackPacket.Packets.Length; i++) | 548 | for (int i = 0; i < ackPacket.Packets.Length; i++) |
560 | AcknowledgePacket(client, ackPacket.Packets[i].ID, now, packet.Header.Resent); | 549 | AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent); |
561 | } | 550 | } |
562 | } | 551 | } |
563 | 552 | ||
@@ -566,27 +555,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
566 | #region ACK Sending | 555 | #region ACK Sending |
567 | 556 | ||
568 | if (packet.Header.Reliable) | 557 | if (packet.Header.Reliable) |
569 | client.PendingAcks.Enqueue((uint)packet.Header.Sequence); | 558 | udpClient.PendingAcks.Enqueue(packet.Header.Sequence); |
570 | 559 | ||
571 | // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, | 560 | // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, |
572 | // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove | 561 | // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove |
573 | // 2*MTU bytes from the value and send ACKs, and finally add the local value back to | 562 | // 2*MTU bytes from the value and send ACKs, and finally add the local value back to |
574 | // client.BytesSinceLastACK. Lockless thread safety | 563 | // client.BytesSinceLastACK. Lockless thread safety |
575 | int bytesSinceLastACK = Interlocked.Exchange(ref client.BytesSinceLastACK, 0); | 564 | int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); |
576 | bytesSinceLastACK += buffer.DataLength; | 565 | bytesSinceLastACK += buffer.DataLength; |
577 | if (bytesSinceLastACK > Packet.MTU * 2) | 566 | if (bytesSinceLastACK > Packet.MTU * 2) |
578 | { | 567 | { |
579 | bytesSinceLastACK -= Packet.MTU * 2; | 568 | bytesSinceLastACK -= Packet.MTU * 2; |
580 | SendAcks(client); | 569 | SendAcks(udpClient); |
581 | } | 570 | } |
582 | Interlocked.Add(ref client.BytesSinceLastACK, bytesSinceLastACK); | 571 | Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK); |
583 | 572 | ||
584 | #endregion ACK Sending | 573 | #endregion ACK Sending |
585 | 574 | ||
586 | #region Incoming Packet Accounting | 575 | #region Incoming Packet Accounting |
587 | 576 | ||
588 | // Check the archive of received reliable packet IDs to see whether we already received this packet | 577 | // Check the archive of received reliable packet IDs to see whether we already received this packet |
589 | if (packet.Header.Reliable && !client.PacketArchive.TryEnqueue(packet.Header.Sequence)) | 578 | if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) |
590 | { | 579 | { |
591 | if (packet.Header.Resent) | 580 | if (packet.Header.Resent) |
592 | m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type); | 581 | m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type); |
@@ -603,7 +592,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
603 | if (packet.Type != PacketType.PacketAck) | 592 | if (packet.Type != PacketType.PacketAck) |
604 | { | 593 | { |
605 | // Inbox insertion | 594 | // Inbox insertion |
606 | packetInbox.Enqueue(new IncomingPacket(client, packet)); | 595 | packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); |
607 | } | 596 | } |
608 | } | 597 | } |
609 | 598 | ||
@@ -623,53 +612,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
623 | 612 | ||
624 | private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint) | 613 | private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint) |
625 | { | 614 | { |
626 | //Slave regions don't accept new clients | 615 | UUID agentID = useCircuitCode.CircuitCode.ID; |
616 | UUID sessionID = useCircuitCode.CircuitCode.SessionID; | ||
617 | uint circuitCode = useCircuitCode.CircuitCode.Code; | ||
618 | |||
627 | if (m_scene.RegionStatus != RegionStatus.SlaveScene) | 619 | if (m_scene.RegionStatus != RegionStatus.SlaveScene) |
628 | { | 620 | { |
629 | AuthenticateResponse sessionInfo; | 621 | AuthenticateResponse sessionInfo; |
630 | bool isNewCircuit = !clients.ContainsKey(remoteEndPoint); | 622 | if (IsClientAuthorized(useCircuitCode, out sessionInfo)) |
631 | |||
632 | if (!IsClientAuthorized(useCircuitCode, out sessionInfo)) | ||
633 | { | 623 | { |
634 | m_log.WarnFormat( | 624 | AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo); |
635 | "[CONNECTION FAILURE]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}", | ||
636 | useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint); | ||
637 | return; | ||
638 | } | 625 | } |
639 | 626 | else | |
640 | if (isNewCircuit) | ||
641 | { | 627 | { |
642 | UUID agentID = useCircuitCode.CircuitCode.ID; | 628 | // Don't create circuits for unauthorized clients |
643 | UUID sessionID = useCircuitCode.CircuitCode.SessionID; | 629 | m_log.WarnFormat( |
644 | uint circuitCode = useCircuitCode.CircuitCode.Code; | 630 | "[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}", |
645 | 631 | useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint); | |
646 | AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo); | ||
647 | } | 632 | } |
648 | } | 633 | } |
634 | else | ||
635 | { | ||
636 | // Slave regions don't accept new clients | ||
637 | m_log.Debug("[LLUDPSERVER]: Slave region " + m_scene.RegionInfo.RegionName + " ignoring UseCircuitCode packet"); | ||
638 | } | ||
649 | } | 639 | } |
650 | 640 | ||
651 | private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) | 641 | private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) |
652 | { | 642 | { |
653 | // Create the LLUDPClient | 643 | // Create the LLUDPClient |
654 | LLUDPClient client = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint); | 644 | LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint); |
655 | |||
656 | // Create the LLClientView | ||
657 | LLClientView clientApi = new LLClientView(remoteEndPoint, m_scene, this, client, sessionInfo, agentID, sessionID, circuitCode); | ||
658 | clientApi.OnViewerEffect += m_scene.ClientManager.ViewerEffectHandler; | ||
659 | clientApi.OnLogout += LogoutHandler; | ||
660 | clientApi.OnConnectionClosed += RemoveClient; | ||
661 | |||
662 | // Start the IClientAPI | ||
663 | m_scene.ClientManager.Add(circuitCode, clientApi); | ||
664 | clientApi.Start(); | ||
665 | 645 | ||
666 | // Give LLUDPClient a reference to IClientAPI | 646 | if (!m_scene.ClientManager.ContainsKey(agentID)) |
667 | client.ClientAPI = clientApi; | 647 | { |
648 | // Create the LLClientView | ||
649 | LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); | ||
650 | client.OnLogout += LogoutHandler; | ||
668 | 651 | ||
669 | // Add the new client to our list of tracked clients | 652 | // Start the IClientAPI |
670 | clients.Add(agentID, client.RemoteEndPoint, client); | 653 | client.Start(); |
654 | } | ||
655 | else | ||
656 | { | ||
657 | m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}", | ||
658 | udpClient.AgentID, remoteEndPoint, circuitCode); | ||
659 | } | ||
660 | } | ||
671 | 661 | ||
672 | m_log.DebugFormat("[LLUDPSERVER]: Added new client {0} to region {1}", agentID, m_scene.RegionInfo.RegionName); | 662 | private void RemoveClient(LLUDPClient udpClient) |
663 | { | ||
664 | // Remove this client from the scene | ||
665 | IClientAPI client; | ||
666 | if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client)) | ||
667 | client.Close(); | ||
673 | } | 668 | } |
674 | 669 | ||
675 | private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend) | 670 | private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend) |
@@ -747,20 +742,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
747 | elapsed500MS = 0; | 742 | elapsed500MS = 0; |
748 | } | 743 | } |
749 | 744 | ||
750 | clients.ForEach( | 745 | m_scene.ClientManager.ForEach( |
751 | delegate(LLUDPClient client) | 746 | delegate(IClientAPI client) |
752 | { | 747 | { |
753 | if (client.DequeueOutgoing()) | 748 | if (client is LLClientView) |
754 | packetSent = true; | ||
755 | if (resendUnacked) | ||
756 | ResendUnacked(client); | ||
757 | if (sendAcks) | ||
758 | { | 749 | { |
759 | SendAcks(client); | 750 | LLUDPClient udpClient = ((LLClientView)client).UDPClient; |
760 | client.SendPacketStats(); | 751 | |
752 | if (udpClient.IsConnected) | ||
753 | { | ||
754 | if (udpClient.DequeueOutgoing()) | ||
755 | packetSent = true; | ||
756 | if (resendUnacked) | ||
757 | ResendUnacked(udpClient); | ||
758 | if (sendAcks) | ||
759 | { | ||
760 | SendAcks(udpClient); | ||
761 | udpClient.SendPacketStats(); | ||
762 | } | ||
763 | if (sendPings) | ||
764 | SendPing(udpClient); | ||
765 | } | ||
761 | } | 766 | } |
762 | if (sendPings) | ||
763 | SendPing(client); | ||
764 | } | 767 | } |
765 | ); | 768 | ); |
766 | 769 | ||
@@ -773,38 +776,48 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
773 | { | 776 | { |
774 | IncomingPacket incomingPacket = (IncomingPacket)state; | 777 | IncomingPacket incomingPacket = (IncomingPacket)state; |
775 | Packet packet = incomingPacket.Packet; | 778 | Packet packet = incomingPacket.Packet; |
776 | LLUDPClient client = incomingPacket.Client; | 779 | LLUDPClient udpClient = incomingPacket.Client; |
780 | IClientAPI client; | ||
777 | 781 | ||
778 | // Sanity check | 782 | // Sanity check |
779 | if (packet == null || client == null || client.ClientAPI == null) | 783 | if (packet == null || udpClient == null) |
780 | { | 784 | { |
781 | m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", Client=\"{1}\", Client.ClientAPI=\"{2}\"", | 785 | m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"", |
782 | packet, client, (client != null) ? client.ClientAPI : null); | 786 | packet, udpClient); |
783 | } | 787 | } |
784 | 788 | ||
785 | try | 789 | // Make sure this client is still alive |
786 | { | 790 | if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client)) |
787 | // Process this packet | ||
788 | client.ClientAPI.ProcessInPacket(packet); | ||
789 | } | ||
790 | catch (ThreadAbortException) | ||
791 | { | 791 | { |
792 | // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down | 792 | try |
793 | m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); | 793 | { |
794 | Stop(); | 794 | // Process this packet |
795 | client.ProcessInPacket(packet); | ||
796 | } | ||
797 | catch (ThreadAbortException) | ||
798 | { | ||
799 | // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down | ||
800 | m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); | ||
801 | Stop(); | ||
802 | } | ||
803 | catch (Exception e) | ||
804 | { | ||
805 | // Don't let a failure in an individual client thread crash the whole sim. | ||
806 | m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type); | ||
807 | m_log.Error(e.Message, e); | ||
808 | } | ||
795 | } | 809 | } |
796 | catch (Exception e) | 810 | else |
797 | { | 811 | { |
798 | // Don't let a failure in an individual client thread crash the whole sim. | 812 | m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID); |
799 | m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", client.AgentID, packet.Type); | ||
800 | m_log.Error(e.Message, e); | ||
801 | } | 813 | } |
802 | } | 814 | } |
803 | 815 | ||
804 | private void LogoutHandler(IClientAPI client) | 816 | private void LogoutHandler(IClientAPI client) |
805 | { | 817 | { |
806 | client.SendLogoutPacket(); | 818 | client.SendLogoutPacket(); |
807 | RemoveClient(client); | 819 | if (client.IsActive) |
820 | RemoveClient(((LLClientView)client).UDPClient); | ||
808 | } | 821 | } |
809 | } | 822 | } |
810 | } | 823 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs index 43a68ec..44a6ed6 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs | |||
@@ -1,419 +1,129 @@ | |||
1 | //--------- Modified Version ------------------- | 1 | /* |
2 | ///* | 2 | * Copyright (c) 2006, Clutch, Inc. |
3 | // * Copyright (c) 2006, Clutch, Inc. | 3 | * Original Author: Jeff Cesnik |
4 | // * Original Author: Jeff Cesnik | 4 | * All rights reserved. |
5 | // * All rights reserved. | 5 | * |
6 | // * | 6 | * - Redistribution and use in source and binary forms, with or without |
7 | // * - Redistribution and use in source and binary forms, with or without | 7 | * modification, are permitted provided that the following conditions are met: |
8 | // * modification, are permitted provided that the following conditions are met: | 8 | * |
9 | // * | 9 | * - Redistributions of source code must retain the above copyright notice, this |
10 | // * - Redistributions of source code must retain the above copyright notice, this | 10 | * list of conditions and the following disclaimer. |
11 | // * list of conditions and the following disclaimer. | 11 | * - Neither the name of the openmetaverse.org nor the names |
12 | // * - Neither the name of the openmetaverse.org nor the names | 12 | * of its contributors may be used to endorse or promote products derived from |
13 | // * of its contributors may be used to endorse or promote products derived from | 13 | * this software without specific prior written permission. |
14 | // * this software without specific prior written permission. | 14 | * |
15 | // * | 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
16 | // * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | // * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | // * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | // * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | // * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | // * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | // * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | // * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | // * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
25 | // * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 25 | * POSSIBILITY OF SUCH DAMAGE. |
26 | // * POSSIBILITY OF SUCH DAMAGE. | 26 | */ |
27 | // */ | ||
28 | 27 | ||
29 | using System; | 28 | using System; |
30 | using System.Net; | 29 | using System.Net; |
31 | using System.Net.Sockets; | 30 | using System.Net.Sockets; |
32 | using System.Threading; | 31 | using System.Threading; |
33 | using OpenMetaverse; | 32 | using log4net; |
34 | 33 | ||
35 | //namespace OpenSim.Region.ClientStack.LindenUDP | 34 | namespace OpenMetaverse |
36 | //{ | ||
37 | // /// <summary> | ||
38 | // /// | ||
39 | // /// </summary> | ||
40 | // public abstract class OpenSimUDPBase | ||
41 | // { | ||
42 | // // these abstract methods must be implemented in a derived class to actually do | ||
43 | // // something with the packets that are sent and received. | ||
44 | // protected abstract void PacketReceived(UDPPacketBuffer buffer); | ||
45 | // protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); | ||
46 | |||
47 | // // the port to listen on | ||
48 | // internal int udpPort; | ||
49 | |||
50 | // // the UDP socket | ||
51 | // private Socket udpSocket; | ||
52 | |||
53 | // // the ReaderWriterLock is used solely for the purposes of shutdown (Stop()). | ||
54 | // // since there are potentially many "reader" threads in the internal .NET IOCP | ||
55 | // // thread pool, this is a cheaper synchronization primitive than using | ||
56 | // // a Mutex object. This allows many UDP socket "reads" concurrently - when | ||
57 | // // Stop() is called, it attempts to obtain a writer lock which will then | ||
58 | // // wait until all outstanding operations are completed before shutting down. | ||
59 | // // this avoids the problem of closing the socket with outstanding operations | ||
60 | // // and trying to catch the inevitable ObjectDisposedException. | ||
61 | // private ReaderWriterLock rwLock = new ReaderWriterLock(); | ||
62 | |||
63 | // // number of outstanding operations. This is a reference count | ||
64 | // // which we use to ensure that the threads exit cleanly. Note that | ||
65 | // // we need this because the threads will potentially still need to process | ||
66 | // // data even after the socket is closed. | ||
67 | // private int rwOperationCount = 0; | ||
68 | |||
69 | // // the all important shutdownFlag. This is synchronized through the ReaderWriterLock. | ||
70 | // private volatile bool shutdownFlag = true; | ||
71 | |||
72 | // // the remote endpoint to communicate with | ||
73 | // protected IPEndPoint remoteEndPoint = null; | ||
74 | |||
75 | |||
76 | // /// <summary> | ||
77 | // /// Initialize the UDP packet handler in server mode | ||
78 | // /// </summary> | ||
79 | // /// <param name="port">Port to listening for incoming UDP packets on</param> | ||
80 | // public OpenSimUDPBase(int port) | ||
81 | // { | ||
82 | // udpPort = port; | ||
83 | // } | ||
84 | |||
85 | // /// <summary> | ||
86 | // /// Initialize the UDP packet handler in client mode | ||
87 | // /// </summary> | ||
88 | // /// <param name="endPoint">Remote UDP server to connect to</param> | ||
89 | // public OpenSimUDPBase(IPEndPoint endPoint) | ||
90 | // { | ||
91 | // remoteEndPoint = endPoint; | ||
92 | // udpPort = 0; | ||
93 | // } | ||
94 | |||
95 | // /// <summary> | ||
96 | // /// | ||
97 | // /// </summary> | ||
98 | // public void Start() | ||
99 | // { | ||
100 | // if (shutdownFlag) | ||
101 | // { | ||
102 | // if (remoteEndPoint == null) | ||
103 | // { | ||
104 | // // Server mode | ||
105 | |||
106 | // // create and bind the socket | ||
107 | // IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); | ||
108 | // udpSocket = new Socket( | ||
109 | // AddressFamily.InterNetwork, | ||
110 | // SocketType.Dgram, | ||
111 | // ProtocolType.Udp); | ||
112 | // udpSocket.Bind(ipep); | ||
113 | // } | ||
114 | // else | ||
115 | // { | ||
116 | // // Client mode | ||
117 | // IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); | ||
118 | // udpSocket = new Socket( | ||
119 | // AddressFamily.InterNetwork, | ||
120 | // SocketType.Dgram, | ||
121 | // ProtocolType.Udp); | ||
122 | // udpSocket.Bind(ipep); | ||
123 | // //udpSocket.Connect(remoteEndPoint); | ||
124 | // } | ||
125 | |||
126 | // // we're not shutting down, we're starting up | ||
127 | // shutdownFlag = false; | ||
128 | |||
129 | // // kick off an async receive. The Start() method will return, the | ||
130 | // // actual receives will occur asynchronously and will be caught in | ||
131 | // // AsyncEndRecieve(). | ||
132 | // AsyncBeginReceive(); | ||
133 | // } | ||
134 | // } | ||
135 | |||
136 | // /// <summary> | ||
137 | // /// | ||
138 | // /// </summary> | ||
139 | // public void Stop() | ||
140 | // { | ||
141 | // if (!shutdownFlag) | ||
142 | // { | ||
143 | // // wait indefinitely for a writer lock. Once this is called, the .NET runtime | ||
144 | // // will deny any more reader locks, in effect blocking all other send/receive | ||
145 | // // threads. Once we have the lock, we set shutdownFlag to inform the other | ||
146 | // // threads that the socket is closed. | ||
147 | // rwLock.AcquireWriterLock(-1); | ||
148 | // shutdownFlag = true; | ||
149 | // udpSocket.Close(); | ||
150 | // rwLock.ReleaseWriterLock(); | ||
151 | |||
152 | // // wait for any pending operations to complete on other | ||
153 | // // threads before exiting. | ||
154 | // const int FORCE_STOP = 100; | ||
155 | // int i = 0; | ||
156 | // while (rwOperationCount > 0 && i < FORCE_STOP) | ||
157 | // { | ||
158 | // Thread.Sleep(10); | ||
159 | // ++i; | ||
160 | // } | ||
161 | |||
162 | // if (i >= FORCE_STOP) | ||
163 | // { | ||
164 | // Logger.Log("UDPBase.Stop() forced shutdown while waiting on pending operations", | ||
165 | // Helpers.LogLevel.Warning); | ||
166 | // } | ||
167 | // } | ||
168 | // } | ||
169 | |||
170 | // /// <summary> | ||
171 | // /// | ||
172 | // /// </summary> | ||
173 | // public bool IsRunning | ||
174 | // { | ||
175 | // get { return !shutdownFlag; } | ||
176 | // } | ||
177 | |||
178 | // private void AsyncBeginReceive() | ||
179 | // { | ||
180 | // // this method actually kicks off the async read on the socket. | ||
181 | // // we aquire a reader lock here to ensure that no other thread | ||
182 | // // is trying to set shutdownFlag and close the socket. | ||
183 | // rwLock.AcquireReaderLock(-1); | ||
184 | |||
185 | // if (!shutdownFlag) | ||
186 | // { | ||
187 | // // increment the count of pending operations | ||
188 | // Interlocked.Increment(ref rwOperationCount); | ||
189 | |||
190 | // // allocate a packet buffer | ||
191 | // //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); | ||
192 | // UDPPacketBuffer buf = new UDPPacketBuffer(); | ||
193 | |||
194 | // try | ||
195 | // { | ||
196 | // // kick off an async read | ||
197 | // udpSocket.BeginReceiveFrom( | ||
198 | // //wrappedBuffer.Instance.Data, | ||
199 | // buf.Data, | ||
200 | // 0, | ||
201 | // UDPPacketBuffer.BUFFER_SIZE, | ||
202 | // SocketFlags.None, | ||
203 | // //ref wrappedBuffer.Instance.RemoteEndPoint, | ||
204 | // ref buf.RemoteEndPoint, | ||
205 | // new AsyncCallback(AsyncEndReceive), | ||
206 | // //wrappedBuffer); | ||
207 | // buf); | ||
208 | // } | ||
209 | // catch (SocketException) | ||
210 | // { | ||
211 | // // something bad happened | ||
212 | // //Logger.Log( | ||
213 | // // "A SocketException occurred in UDPServer.AsyncBeginReceive()", | ||
214 | // // Helpers.LogLevel.Error, se); | ||
215 | |||
216 | // // an error occurred, therefore the operation is void. Decrement the reference count. | ||
217 | // Interlocked.Decrement(ref rwOperationCount); | ||
218 | // } | ||
219 | // } | ||
220 | |||
221 | // // we're done with the socket for now, release the reader lock. | ||
222 | // rwLock.ReleaseReaderLock(); | ||
223 | // } | ||
224 | |||
225 | // private void AsyncEndReceive(IAsyncResult iar) | ||
226 | // { | ||
227 | // // Asynchronous receive operations will complete here through the call | ||
228 | // // to AsyncBeginReceive | ||
229 | |||
230 | // // aquire a reader lock | ||
231 | // rwLock.AcquireReaderLock(-1); | ||
232 | |||
233 | // if (!shutdownFlag) | ||
234 | // { | ||
235 | // // get the buffer that was created in AsyncBeginReceive | ||
236 | // // this is the received data | ||
237 | // //WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState; | ||
238 | // //UDPPacketBuffer buffer = wrappedBuffer.Instance; | ||
239 | // UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; | ||
240 | |||
241 | // try | ||
242 | // { | ||
243 | // // get the length of data actually read from the socket, store it with the | ||
244 | // // buffer | ||
245 | // buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); | ||
246 | |||
247 | // // this operation is now complete, decrement the reference count | ||
248 | // Interlocked.Decrement(ref rwOperationCount); | ||
249 | |||
250 | // // we're done with the socket, release the reader lock | ||
251 | // rwLock.ReleaseReaderLock(); | ||
252 | |||
253 | // // call the abstract method PacketReceived(), passing the buffer that | ||
254 | // // has just been filled from the socket read. | ||
255 | // PacketReceived(buffer); | ||
256 | // } | ||
257 | // catch (SocketException) | ||
258 | // { | ||
259 | // // an error occurred, therefore the operation is void. Decrement the reference count. | ||
260 | // Interlocked.Decrement(ref rwOperationCount); | ||
261 | |||
262 | // // we're done with the socket for now, release the reader lock. | ||
263 | // rwLock.ReleaseReaderLock(); | ||
264 | // } | ||
265 | // finally | ||
266 | // { | ||
267 | // // start another receive - this keeps the server going! | ||
268 | // AsyncBeginReceive(); | ||
269 | |||
270 | // //wrappedBuffer.Dispose(); | ||
271 | // } | ||
272 | // } | ||
273 | // else | ||
274 | // { | ||
275 | // // nothing bad happened, but we are done with the operation | ||
276 | // // decrement the reference count and release the reader lock | ||
277 | // Interlocked.Decrement(ref rwOperationCount); | ||
278 | // rwLock.ReleaseReaderLock(); | ||
279 | // } | ||
280 | // } | ||
281 | |||
282 | // public void AsyncBeginSend(UDPPacketBuffer buf) | ||
283 | // { | ||
284 | // rwLock.AcquireReaderLock(-1); | ||
285 | |||
286 | // if (!shutdownFlag) | ||
287 | // { | ||
288 | // try | ||
289 | // { | ||
290 | // Interlocked.Increment(ref rwOperationCount); | ||
291 | // udpSocket.BeginSendTo( | ||
292 | // buf.Data, | ||
293 | // 0, | ||
294 | // buf.DataLength, | ||
295 | // SocketFlags.None, | ||
296 | // buf.RemoteEndPoint, | ||
297 | // new AsyncCallback(AsyncEndSend), | ||
298 | // buf); | ||
299 | // } | ||
300 | // catch (SocketException) | ||
301 | // { | ||
302 | // //Logger.Log( | ||
303 | // // "A SocketException occurred in UDPServer.AsyncBeginSend()", | ||
304 | // // Helpers.LogLevel.Error, se); | ||
305 | // } | ||
306 | // } | ||
307 | |||
308 | // rwLock.ReleaseReaderLock(); | ||
309 | // } | ||
310 | |||
311 | // private void AsyncEndSend(IAsyncResult iar) | ||
312 | // { | ||
313 | // rwLock.AcquireReaderLock(-1); | ||
314 | |||
315 | // if (!shutdownFlag) | ||
316 | // { | ||
317 | // UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; | ||
318 | |||
319 | // try | ||
320 | // { | ||
321 | // int bytesSent = udpSocket.EndSendTo(iar); | ||
322 | |||
323 | // // note that call to the abstract PacketSent() method - we are passing the number | ||
324 | // // of bytes sent in a separate parameter, since we can't use buffer.DataLength which | ||
325 | // // is the number of bytes to send (or bytes received depending upon whether this | ||
326 | // // buffer was part of a send or a receive). | ||
327 | // PacketSent(buffer, bytesSent); | ||
328 | // } | ||
329 | // catch (SocketException) | ||
330 | // { | ||
331 | // //Logger.Log( | ||
332 | // // "A SocketException occurred in UDPServer.AsyncEndSend()", | ||
333 | // // Helpers.LogLevel.Error, se); | ||
334 | // } | ||
335 | // } | ||
336 | |||
337 | // Interlocked.Decrement(ref rwOperationCount); | ||
338 | // rwLock.ReleaseReaderLock(); | ||
339 | // } | ||
340 | // } | ||
341 | //} | ||
342 | |||
343 | //--------- Original Version ------------------- | ||
344 | |||
345 | |||
346 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
347 | { | 35 | { |
348 | /// <summary> | 36 | /// <summary> |
349 | /// | 37 | /// Base UDP server |
350 | /// </summary> | 38 | /// </summary> |
351 | public abstract class OpenSimUDPBase | 39 | public abstract class OpenSimUDPBase |
352 | { | 40 | { |
353 | // these abstract methods must be implemented in a derived class to actually do | 41 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); |
354 | // something with the packets that are sent and received. | 42 | |
43 | /// <summary> | ||
44 | /// This method is called when an incoming packet is received | ||
45 | /// </summary> | ||
46 | /// <param name="buffer">Incoming packet buffer</param> | ||
355 | protected abstract void PacketReceived(UDPPacketBuffer buffer); | 47 | protected abstract void PacketReceived(UDPPacketBuffer buffer); |
48 | |||
49 | /// <summary> | ||
50 | /// This method is called when an outgoing packet is sent | ||
51 | /// </summary> | ||
52 | /// <param name="buffer">Outgoing packet buffer</param> | ||
53 | /// <param name="bytesSent">Number of bytes written to the wire</param> | ||
356 | protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); | 54 | protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); |
357 | 55 | ||
358 | // the port to listen on | 56 | /// <summary>UDP port to bind to in server mode</summary> |
359 | internal int udpPort; | 57 | protected int m_udpPort; |
360 | 58 | ||
361 | // the UDP socket | 59 | /// <summary>Local IP address to bind to in server mode</summary> |
362 | private Socket udpSocket; | 60 | protected IPAddress m_localBindAddress; |
363 | 61 | ||
364 | // the all important shutdownFlag. | 62 | /// <summary>UDP socket, used in either client or server mode</summary> |
365 | private volatile bool shutdownFlag = true; | 63 | private Socket m_udpSocket; |
366 | 64 | ||
367 | // the remote endpoint to communicate with | 65 | /// <summary>The all important shutdown flag</summary> |
368 | protected IPEndPoint remoteEndPoint = null; | 66 | private volatile bool m_shutdownFlag = true; |
369 | 67 | ||
370 | /// <summary> | 68 | /// <summary>Returns true if the server is currently listening, otherwise false</summary> |
371 | /// Initialize the UDP packet handler in server mode | 69 | public bool IsRunning { get { return !m_shutdownFlag; } } |
372 | /// </summary> | ||
373 | /// <param name="port">Port to listening for incoming UDP packets on</param> | ||
374 | public OpenSimUDPBase(int port) | ||
375 | { | ||
376 | udpPort = port; | ||
377 | } | ||
378 | 70 | ||
379 | /// <summary> | 71 | /// <summary> |
380 | /// Initialize the UDP packet handler in client mode | 72 | /// Default constructor |
381 | /// </summary> | 73 | /// </summary> |
382 | /// <param name="endPoint">Remote UDP server to connect to</param> | 74 | /// <param name="bindAddress">Local IP address to bind the server to</param> |
383 | public OpenSimUDPBase(IPEndPoint endPoint) | 75 | /// <param name="port">Port to listening for incoming UDP packets on</param> |
76 | /// | ||
77 | public OpenSimUDPBase(IPAddress bindAddress, int port) | ||
384 | { | 78 | { |
385 | remoteEndPoint = endPoint; | 79 | m_localBindAddress = bindAddress; |
386 | udpPort = 0; | 80 | m_udpPort = port; |
387 | } | 81 | } |
388 | 82 | ||
389 | /// <summary> | 83 | /// <summary> |
390 | /// | 84 | /// Start the UDP server |
391 | /// </summary> | 85 | /// </summary> |
392 | public void Start() | 86 | /// <param name="recvBufferSize">The size of the receive buffer for |
87 | /// the UDP socket. This value is passed up to the operating system | ||
88 | /// and used in the system networking stack. Use zero to leave this | ||
89 | /// value as the default</param> | ||
90 | /// <remarks>This method will attempt to set the SIO_UDP_CONNRESET flag | ||
91 | /// on the socket to get newer versions of Windows to behave in a sane | ||
92 | /// manner (not throwing an exception when the remote side resets the | ||
93 | /// connection). This call is ignored on Mono where the flag is not | ||
94 | /// necessary</remarks> | ||
95 | public void Start(int recvBufferSize) | ||
393 | { | 96 | { |
394 | if (shutdownFlag) | 97 | if (m_shutdownFlag) |
395 | { | 98 | { |
396 | const int SIO_UDP_CONNRESET = -1744830452; | 99 | const int SIO_UDP_CONNRESET = -1744830452; |
397 | 100 | ||
398 | IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); | 101 | IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); |
399 | udpSocket = new Socket( | 102 | |
103 | m_udpSocket = new Socket( | ||
400 | AddressFamily.InterNetwork, | 104 | AddressFamily.InterNetwork, |
401 | SocketType.Dgram, | 105 | SocketType.Dgram, |
402 | ProtocolType.Udp); | 106 | ProtocolType.Udp); |
107 | |||
403 | try | 108 | try |
404 | { | 109 | { |
405 | // this udp socket flag is not supported under mono, | 110 | // This udp socket flag is not supported under mono, |
406 | // so we'll catch the exception and continue | 111 | // so we'll catch the exception and continue |
407 | udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); | 112 | m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); |
113 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set"); | ||
408 | } | 114 | } |
409 | catch (SocketException) | 115 | catch (SocketException) |
410 | { | 116 | { |
411 | Logger.DebugLog("UDP SIO_UDP_CONNRESET flag not supported on this platform"); | 117 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); |
412 | } | 118 | } |
413 | udpSocket.Bind(ipep); | 119 | |
120 | if (recvBufferSize != 0) | ||
121 | m_udpSocket.ReceiveBufferSize = recvBufferSize; | ||
122 | |||
123 | m_udpSocket.Bind(ipep); | ||
414 | 124 | ||
415 | // we're not shutting down, we're starting up | 125 | // we're not shutting down, we're starting up |
416 | shutdownFlag = false; | 126 | m_shutdownFlag = false; |
417 | 127 | ||
418 | // kick off an async receive. The Start() method will return, the | 128 | // kick off an async receive. The Start() method will return, the |
419 | // actual receives will occur asynchronously and will be caught in | 129 | // actual receives will occur asynchronously and will be caught in |
@@ -423,41 +133,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
423 | } | 133 | } |
424 | 134 | ||
425 | /// <summary> | 135 | /// <summary> |
426 | /// | 136 | /// Stops the UDP server |
427 | /// </summary> | 137 | /// </summary> |
428 | public void Stop() | 138 | public void Stop() |
429 | { | 139 | { |
430 | if (!shutdownFlag) | 140 | if (!m_shutdownFlag) |
431 | { | 141 | { |
432 | // wait indefinitely for a writer lock. Once this is called, the .NET runtime | 142 | // wait indefinitely for a writer lock. Once this is called, the .NET runtime |
433 | // will deny any more reader locks, in effect blocking all other send/receive | 143 | // will deny any more reader locks, in effect blocking all other send/receive |
434 | // threads. Once we have the lock, we set shutdownFlag to inform the other | 144 | // threads. Once we have the lock, we set shutdownFlag to inform the other |
435 | // threads that the socket is closed. | 145 | // threads that the socket is closed. |
436 | shutdownFlag = true; | 146 | m_shutdownFlag = true; |
437 | udpSocket.Close(); | 147 | m_udpSocket.Close(); |
438 | } | 148 | } |
439 | } | 149 | } |
440 | 150 | ||
441 | /// <summary> | ||
442 | /// | ||
443 | /// </summary> | ||
444 | public bool IsRunning | ||
445 | { | ||
446 | get { return !shutdownFlag; } | ||
447 | } | ||
448 | |||
449 | private void AsyncBeginReceive() | 151 | private void AsyncBeginReceive() |
450 | { | 152 | { |
451 | // allocate a packet buffer | 153 | // allocate a packet buffer |
452 | //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); | 154 | //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); |
453 | UDPPacketBuffer buf = new UDPPacketBuffer(); | 155 | UDPPacketBuffer buf = new UDPPacketBuffer(); |
454 | 156 | ||
455 | if (!shutdownFlag) | 157 | if (!m_shutdownFlag) |
456 | { | 158 | { |
457 | try | 159 | try |
458 | { | 160 | { |
459 | // kick off an async read | 161 | // kick off an async read |
460 | udpSocket.BeginReceiveFrom( | 162 | m_udpSocket.BeginReceiveFrom( |
461 | //wrappedBuffer.Instance.Data, | 163 | //wrappedBuffer.Instance.Data, |
462 | buf.Data, | 164 | buf.Data, |
463 | 0, | 165 | 0, |
@@ -472,13 +174,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
472 | { | 174 | { |
473 | if (e.SocketErrorCode == SocketError.ConnectionReset) | 175 | if (e.SocketErrorCode == SocketError.ConnectionReset) |
474 | { | 176 | { |
475 | Logger.Log("SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + udpPort, Helpers.LogLevel.Error); | 177 | m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort); |
476 | bool salvaged = false; | 178 | bool salvaged = false; |
477 | while (!salvaged) | 179 | while (!salvaged) |
478 | { | 180 | { |
479 | try | 181 | try |
480 | { | 182 | { |
481 | udpSocket.BeginReceiveFrom( | 183 | m_udpSocket.BeginReceiveFrom( |
482 | //wrappedBuffer.Instance.Data, | 184 | //wrappedBuffer.Instance.Data, |
483 | buf.Data, | 185 | buf.Data, |
484 | 0, | 186 | 0, |
@@ -494,7 +196,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
494 | catch (ObjectDisposedException) { return; } | 196 | catch (ObjectDisposedException) { return; } |
495 | } | 197 | } |
496 | 198 | ||
497 | Logger.Log("Salvaged the UDP listener on port " + udpPort, Helpers.LogLevel.Info); | 199 | m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); |
498 | } | 200 | } |
499 | } | 201 | } |
500 | catch (ObjectDisposedException) { } | 202 | catch (ObjectDisposedException) { } |
@@ -505,7 +207,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
505 | { | 207 | { |
506 | // Asynchronous receive operations will complete here through the call | 208 | // Asynchronous receive operations will complete here through the call |
507 | // to AsyncBeginReceive | 209 | // to AsyncBeginReceive |
508 | if (!shutdownFlag) | 210 | if (!m_shutdownFlag) |
509 | { | 211 | { |
510 | // start another receive - this keeps the server going! | 212 | // start another receive - this keeps the server going! |
511 | AsyncBeginReceive(); | 213 | AsyncBeginReceive(); |
@@ -520,7 +222,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
520 | { | 222 | { |
521 | // get the length of data actually read from the socket, store it with the | 223 | // get the length of data actually read from the socket, store it with the |
522 | // buffer | 224 | // buffer |
523 | buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); | 225 | buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); |
524 | 226 | ||
525 | // call the abstract method PacketReceived(), passing the buffer that | 227 | // call the abstract method PacketReceived(), passing the buffer that |
526 | // has just been filled from the socket read. | 228 | // has just been filled from the socket read. |
@@ -529,16 +231,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
529 | catch (SocketException) { } | 231 | catch (SocketException) { } |
530 | catch (ObjectDisposedException) { } | 232 | catch (ObjectDisposedException) { } |
531 | //finally { wrappedBuffer.Dispose(); } | 233 | //finally { wrappedBuffer.Dispose(); } |
234 | |||
532 | } | 235 | } |
533 | } | 236 | } |
534 | 237 | ||
535 | public void AsyncBeginSend(UDPPacketBuffer buf) | 238 | public void AsyncBeginSend(UDPPacketBuffer buf) |
536 | { | 239 | { |
537 | if (!shutdownFlag) | 240 | if (!m_shutdownFlag) |
538 | { | 241 | { |
539 | try | 242 | try |
540 | { | 243 | { |
541 | udpSocket.BeginSendTo( | 244 | m_udpSocket.BeginSendTo( |
542 | buf.Data, | 245 | buf.Data, |
543 | 0, | 246 | 0, |
544 | buf.DataLength, | 247 | buf.DataLength, |
@@ -557,7 +260,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
557 | try | 260 | try |
558 | { | 261 | { |
559 | UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; | 262 | UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; |
560 | int bytesSent = udpSocket.EndSendTo(result); | 263 | int bytesSent = m_udpSocket.EndSendTo(result); |
561 | 264 | ||
562 | PacketSent(buf, bytesSent); | 265 | PacketSent(buf, bytesSent); |
563 | } | 266 | } |
@@ -566,4 +269,3 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
566 | } | 269 | } |
567 | } | 270 | } |
568 | } | 271 | } |
569 | |||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs index 858a03c..008d827 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using OpenSim.Framework; | ||
29 | using Nini.Config; | 30 | using Nini.Config; |
30 | 31 | ||
31 | namespace OpenSim.Region.ClientStack.LindenUDP | 32 | namespace OpenSim.Region.ClientStack.LindenUDP |
@@ -45,12 +46,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
45 | public int Wind; | 46 | public int Wind; |
46 | /// <summary>Drip rate for cloud packets</summary> | 47 | /// <summary>Drip rate for cloud packets</summary> |
47 | public int Cloud; | 48 | public int Cloud; |
48 | /// <summary>Drip rate for task (state and transaction) packets</summary> | 49 | /// <summary>Drip rate for task packets</summary> |
49 | public int Task; | 50 | public int Task; |
50 | /// <summary>Drip rate for texture packets</summary> | 51 | /// <summary>Drip rate for texture packets</summary> |
51 | public int Texture; | 52 | public int Texture; |
52 | /// <summary>Drip rate for asset packets</summary> | 53 | /// <summary>Drip rate for asset packets</summary> |
53 | public int Asset; | 54 | public int Asset; |
55 | /// <summary>Drip rate for state packets</summary> | ||
56 | public int State; | ||
57 | /// <summary>Drip rate for the parent token bucket</summary> | ||
58 | public int Total; | ||
54 | 59 | ||
55 | /// <summary>Maximum burst rate for resent packets</summary> | 60 | /// <summary>Maximum burst rate for resent packets</summary> |
56 | public int ResendLimit; | 61 | public int ResendLimit; |
@@ -66,6 +71,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
66 | public int TextureLimit; | 71 | public int TextureLimit; |
67 | /// <summary>Maximum burst rate for asset packets</summary> | 72 | /// <summary>Maximum burst rate for asset packets</summary> |
68 | public int AssetLimit; | 73 | public int AssetLimit; |
74 | /// <summary>Maximum burst rate for state packets</summary> | ||
75 | public int StateLimit; | ||
76 | /// <summary>Burst rate for the parent token bucket</summary> | ||
77 | public int TotalLimit; | ||
69 | 78 | ||
70 | /// <summary> | 79 | /// <summary> |
71 | /// Default constructor | 80 | /// Default constructor |
@@ -77,23 +86,81 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
77 | { | 86 | { |
78 | IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"]; | 87 | IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"]; |
79 | 88 | ||
80 | Resend = throttleConfig.GetInt("ResendDefault", 12500); | 89 | Resend = throttleConfig.GetInt("resend_default", 12500); |
81 | Land = throttleConfig.GetInt("LandDefault", 500); | 90 | Land = throttleConfig.GetInt("land_default", 500); |
82 | Wind = throttleConfig.GetInt("WindDefault", 500); | 91 | Wind = throttleConfig.GetInt("wind_default", 500); |
83 | Cloud = throttleConfig.GetInt("CloudDefault", 500); | 92 | Cloud = throttleConfig.GetInt("cloud_default", 500); |
84 | Task = throttleConfig.GetInt("TaskDefault", 500); | 93 | Task = throttleConfig.GetInt("task_default", 500); |
85 | Texture = throttleConfig.GetInt("TextureDefault", 500); | 94 | Texture = throttleConfig.GetInt("texture_default", 500); |
86 | Asset = throttleConfig.GetInt("AssetDefault", 500); | 95 | Asset = throttleConfig.GetInt("asset_default", 500); |
96 | State = throttleConfig.GetInt("state_default", 500); | ||
87 | 97 | ||
88 | ResendLimit = throttleConfig.GetInt("ResendLimit", 18750); | 98 | Total = throttleConfig.GetInt("client_throttle_max_bps", 0); |
89 | LandLimit = throttleConfig.GetInt("LandLimit", 29750); | 99 | |
90 | WindLimit = throttleConfig.GetInt("WindLimit", 18750); | 100 | ResendLimit = throttleConfig.GetInt("resend_limit", 18750); |
91 | CloudLimit = throttleConfig.GetInt("CloudLimit", 18750); | 101 | LandLimit = throttleConfig.GetInt("land_limit", 29750); |
92 | TaskLimit = throttleConfig.GetInt("TaskLimit", 55750); | 102 | WindLimit = throttleConfig.GetInt("wind_limit", 18750); |
93 | TextureLimit = throttleConfig.GetInt("TextureLimit", 55750); | 103 | CloudLimit = throttleConfig.GetInt("cloud_limit", 18750); |
94 | AssetLimit = throttleConfig.GetInt("AssetLimit", 27500); | 104 | TaskLimit = throttleConfig.GetInt("task_limit", 18750); |
105 | TextureLimit = throttleConfig.GetInt("texture_limit", 55750); | ||
106 | AssetLimit = throttleConfig.GetInt("asset_limit", 27500); | ||
107 | State = throttleConfig.GetInt("state_limit", 37000); | ||
108 | |||
109 | TotalLimit = throttleConfig.GetInt("client_throttle_max_bps", 0); | ||
95 | } | 110 | } |
96 | catch (Exception) { } | 111 | catch (Exception) { } |
97 | } | 112 | } |
113 | |||
114 | public int GetRate(ThrottleOutPacketType type) | ||
115 | { | ||
116 | switch (type) | ||
117 | { | ||
118 | case ThrottleOutPacketType.Resend: | ||
119 | return Resend; | ||
120 | case ThrottleOutPacketType.Land: | ||
121 | return Land; | ||
122 | case ThrottleOutPacketType.Wind: | ||
123 | return Wind; | ||
124 | case ThrottleOutPacketType.Cloud: | ||
125 | return Cloud; | ||
126 | case ThrottleOutPacketType.Task: | ||
127 | return Task; | ||
128 | case ThrottleOutPacketType.Texture: | ||
129 | return Texture; | ||
130 | case ThrottleOutPacketType.Asset: | ||
131 | return Asset; | ||
132 | case ThrottleOutPacketType.State: | ||
133 | return State; | ||
134 | case ThrottleOutPacketType.Unknown: | ||
135 | default: | ||
136 | return 0; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | public int GetLimit(ThrottleOutPacketType type) | ||
141 | { | ||
142 | switch (type) | ||
143 | { | ||
144 | case ThrottleOutPacketType.Resend: | ||
145 | return ResendLimit; | ||
146 | case ThrottleOutPacketType.Land: | ||
147 | return LandLimit; | ||
148 | case ThrottleOutPacketType.Wind: | ||
149 | return WindLimit; | ||
150 | case ThrottleOutPacketType.Cloud: | ||
151 | return CloudLimit; | ||
152 | case ThrottleOutPacketType.Task: | ||
153 | return TaskLimit; | ||
154 | case ThrottleOutPacketType.Texture: | ||
155 | return TextureLimit; | ||
156 | case ThrottleOutPacketType.Asset: | ||
157 | return AssetLimit; | ||
158 | case ThrottleOutPacketType.State: | ||
159 | return StateLimit; | ||
160 | case ThrottleOutPacketType.Unknown: | ||
161 | default: | ||
162 | return 0; | ||
163 | } | ||
164 | } | ||
98 | } | 165 | } |
99 | } | 166 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs index 195ca57..f3242c1 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs | |||
@@ -103,6 +103,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
103 | } | 103 | } |
104 | 104 | ||
105 | /// <summary> | 105 | /// <summary> |
106 | /// Removes all elements from the collection | ||
107 | /// </summary> | ||
108 | public void Clear() | ||
109 | { | ||
110 | lock (SyncRoot) | ||
111 | packets.Clear(); | ||
112 | } | ||
113 | |||
114 | /// <summary> | ||
106 | /// Gets the packet with the lowest sequence number | 115 | /// Gets the packet with the lowest sequence number |
107 | /// </summary> | 116 | /// </summary> |
108 | /// <returns>The packet with the lowest sequence number, or null if the | 117 | /// <returns>The packet with the lowest sequence number, or null if the |
diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs index f941728..7855862 100644 --- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs | |||
@@ -36,6 +36,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods | |||
36 | { | 36 | { |
37 | public class GodsModule : IRegionModule, IGodsModule | 37 | public class GodsModule : IRegionModule, IGodsModule |
38 | { | 38 | { |
39 | /// <summary>Special UUID for actions that apply to all agents</summary> | ||
40 | private static readonly UUID ALL_AGENTS = new UUID("44e87126-e794-4ded-05b3-7c42da3d5cdb"); | ||
41 | |||
39 | protected Scene m_scene; | 42 | protected Scene m_scene; |
40 | protected IDialogModule m_dialogModule; | 43 | protected IDialogModule m_dialogModule; |
41 | 44 | ||
@@ -99,8 +102,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods | |||
99 | /// <param name="reason">The message to send to the user after it's been turned into a field</param> | 102 | /// <param name="reason">The message to send to the user after it's been turned into a field</param> |
100 | public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason) | 103 | public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason) |
101 | { | 104 | { |
102 | // For some reason the client sends this seemingly hard coded UUID for kicking everyone. Dun-know. | 105 | UUID kickUserID = ALL_AGENTS; |
103 | UUID kickUserID = new UUID("44e87126e7944ded05b37c42da3d5cdb"); | ||
104 | 106 | ||
105 | ScenePresence sp = m_scene.GetScenePresence(agentID); | 107 | ScenePresence sp = m_scene.GetScenePresence(agentID); |
106 | 108 | ||
@@ -110,15 +112,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods | |||
110 | { | 112 | { |
111 | if (agentID == kickUserID) | 113 | if (agentID == kickUserID) |
112 | { | 114 | { |
113 | m_scene.ClientManager.ForEachClient( | 115 | string reasonStr = Utils.BytesToString(reason); |
116 | |||
117 | m_scene.ClientManager.ForEach( | ||
114 | delegate(IClientAPI controller) | 118 | delegate(IClientAPI controller) |
115 | { | 119 | { |
116 | if (controller.AgentId != godID) | 120 | if (controller.AgentId != godID) |
117 | controller.Kick(Utils.BytesToString(reason)); | 121 | controller.Kick(reasonStr); |
118 | } | 122 | } |
119 | ); | 123 | ); |
120 | 124 | ||
121 | // This is a bit crude. It seems the client will be null before it actually stops the thread | 125 | // This is a bit crude. It seems the client will be null before it actually stops the thread |
122 | // The thread will kill itself eventually :/ | 126 | // The thread will kill itself eventually :/ |
123 | // Is there another way to make sure *all* clients get this 'inter region' message? | 127 | // Is there another way to make sure *all* clients get this 'inter region' message? |
124 | m_scene.ForEachScenePresence( | 128 | m_scene.ForEachScenePresence( |
@@ -128,7 +132,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods | |||
128 | { | 132 | { |
129 | // Possibly this should really be p.Close() though that method doesn't send a close | 133 | // Possibly this should really be p.Close() though that method doesn't send a close |
130 | // to the client | 134 | // to the client |
131 | p.ControllingClient.Close(true); | 135 | p.ControllingClient.Close(); |
132 | } | 136 | } |
133 | } | 137 | } |
134 | ); | 138 | ); |
@@ -138,7 +142,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods | |||
138 | m_scene.SceneGraph.removeUserCount(!sp.IsChildAgent); | 142 | m_scene.SceneGraph.removeUserCount(!sp.IsChildAgent); |
139 | 143 | ||
140 | sp.ControllingClient.Kick(Utils.BytesToString(reason)); | 144 | sp.ControllingClient.Kick(Utils.BytesToString(reason)); |
141 | sp.ControllingClient.Close(true); | 145 | sp.ControllingClient.Close(); |
142 | } | 146 | } |
143 | } | 147 | } |
144 | else | 148 | else |
diff --git a/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs b/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs index 7d6f150..d636b1c 100644 --- a/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs +++ b/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs | |||
@@ -1267,7 +1267,7 @@ namespace OpenSim.Region.CoreModules.InterGrid | |||
1267 | if (avToBeKilled.IsChildAgent) | 1267 | if (avToBeKilled.IsChildAgent) |
1268 | { | 1268 | { |
1269 | m_mod.DeleteOGPState(avUUID); | 1269 | m_mod.DeleteOGPState(avUUID); |
1270 | avToBeKilled.ControllingClient.Close(true); | 1270 | avToBeKilled.ControllingClient.Close(); |
1271 | } | 1271 | } |
1272 | } | 1272 | } |
1273 | } | 1273 | } |
diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index b885420..9b565ed 100644 --- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs | |||
@@ -57,7 +57,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
57 | public string body; | 57 | public string body; |
58 | public int responseCode; | 58 | public int responseCode; |
59 | public string responseBody; | 59 | public string responseBody; |
60 | public ManualResetEvent ev; | 60 | //public ManualResetEvent ev; |
61 | public bool requestDone; | 61 | public bool requestDone; |
62 | public int startTime; | 62 | public int startTime; |
63 | public string uri; | 63 | public string uri; |
@@ -456,7 +456,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
456 | requestData.headers["x-query-string"] = queryString; | 456 | requestData.headers["x-query-string"] = queryString; |
457 | requestData.headers["x-script-url"] = url.url; | 457 | requestData.headers["x-script-url"] = url.url; |
458 | 458 | ||
459 | requestData.ev = new ManualResetEvent(false); | 459 | //requestData.ev = new ManualResetEvent(false); |
460 | lock (url.requests) | 460 | lock (url.requests) |
461 | { | 461 | { |
462 | url.requests.Add(requestID, requestData); | 462 | url.requests.Add(requestID, requestData); |
diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index 8ad4844..d651fd4 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs | |||
@@ -813,7 +813,7 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
813 | { | 813 | { |
814 | } | 814 | } |
815 | 815 | ||
816 | public void Close(bool ShutdownCircuit) | 816 | public void Close() |
817 | { | 817 | { |
818 | } | 818 | } |
819 | 819 | ||
@@ -833,6 +833,11 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
833 | set { m_circuitCode = value; } | 833 | set { m_circuitCode = value; } |
834 | } | 834 | } |
835 | 835 | ||
836 | public IPEndPoint RemoteEndPoint | ||
837 | { | ||
838 | get { return new IPEndPoint(IPAddress.Loopback, (ushort)m_circuitCode); } | ||
839 | } | ||
840 | |||
836 | public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message) | 841 | public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message) |
837 | { | 842 | { |
838 | 843 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index 4ae4dc3..ac89f7b 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs | |||
@@ -390,6 +390,32 @@ namespace OpenSim.Region.Framework.Scenes | |||
390 | EventManager.TriggerScriptReset(part.LocalId, itemID); | 390 | EventManager.TriggerScriptReset(part.LocalId, itemID); |
391 | } | 391 | } |
392 | } | 392 | } |
393 | |||
394 | void ProcessViewerEffect(IClientAPI remoteClient, List<ViewerEffectEventHandlerArg> args) | ||
395 | { | ||
396 | // TODO: don't create new blocks if recycling an old packet | ||
397 | List<ViewerEffectPacket.EffectBlock> effectBlock = new List<ViewerEffectPacket.EffectBlock>(); | ||
398 | for (int i = 0; i < args.Count; i++) | ||
399 | { | ||
400 | ViewerEffectPacket.EffectBlock effect = new ViewerEffectPacket.EffectBlock(); | ||
401 | effect.AgentID = args[i].AgentID; | ||
402 | effect.Color = args[i].Color; | ||
403 | effect.Duration = args[i].Duration; | ||
404 | effect.ID = args[i].ID; | ||
405 | effect.Type = args[i].Type; | ||
406 | effect.TypeData = args[i].TypeData; | ||
407 | effectBlock.Add(effect); | ||
408 | } | ||
409 | ViewerEffectPacket.EffectBlock[] effectBlockArray = effectBlock.ToArray(); | ||
410 | |||
411 | ClientManager.ForEach( | ||
412 | delegate(IClientAPI client) | ||
413 | { | ||
414 | if (client.AgentId != remoteClient.AgentId) | ||
415 | client.SendViewerEffect(effectBlockArray); | ||
416 | } | ||
417 | ); | ||
418 | } | ||
393 | 419 | ||
394 | /// <summary> | 420 | /// <summary> |
395 | /// Handle a fetch inventory request from the client | 421 | /// Handle a fetch inventory request from the client |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 04eb93f..14e4534 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -117,6 +117,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
117 | private volatile bool m_backingup = false; | 117 | private volatile bool m_backingup = false; |
118 | 118 | ||
119 | private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>(); | 119 | private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>(); |
120 | |||
121 | private Dictionary<UUID, SceneObjectGroup> m_groupsWithTargets = new Dictionary<UUID, SceneObjectGroup>(); | ||
120 | 122 | ||
121 | protected string m_simulatorVersion = "OpenSimulator Server"; | 123 | protected string m_simulatorVersion = "OpenSimulator Server"; |
122 | 124 | ||
@@ -246,8 +248,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
246 | 248 | ||
247 | private int m_update_physics = 1; | 249 | private int m_update_physics = 1; |
248 | private int m_update_entitymovement = 1; | 250 | private int m_update_entitymovement = 1; |
249 | private int m_update_entities = 1; // Run through all objects checking for updates | 251 | private int m_update_objects = 1; // Update objects which have scheduled themselves for updates |
250 | private int m_update_entitiesquick = 200; // Run through objects that have scheduled updates checking for updates | ||
251 | private int m_update_presences = 1; // Update scene presence movements | 252 | private int m_update_presences = 1; // Update scene presence movements |
252 | private int m_update_events = 1; | 253 | private int m_update_events = 1; |
253 | private int m_update_backup = 200; | 254 | private int m_update_backup = 200; |
@@ -867,7 +868,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
867 | Thread.Sleep(500); | 868 | Thread.Sleep(500); |
868 | 869 | ||
869 | // Stop all client threads. | 870 | // Stop all client threads. |
870 | ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(true); }); | 871 | ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(); }); |
871 | 872 | ||
872 | // Stop updating the scene objects and agents. | 873 | // Stop updating the scene objects and agents. |
873 | //m_heartbeatTimer.Close(); | 874 | //m_heartbeatTimer.Close(); |
@@ -979,28 +980,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
979 | maintc = Environment.TickCount; | 980 | maintc = Environment.TickCount; |
980 | 981 | ||
981 | TimeSpan SinceLastFrame = DateTime.Now - m_lastupdate; | 982 | TimeSpan SinceLastFrame = DateTime.Now - m_lastupdate; |
982 | // Aquire a lock so only one update call happens at once | ||
983 | //updateLock.WaitOne(); | ||
984 | float physicsFPS = 0; | 983 | float physicsFPS = 0; |
985 | //m_log.Info("sadfadf" + m_neighbours.Count.ToString()); | ||
986 | int agentsInScene = m_sceneGraph.GetRootAgentCount() + m_sceneGraph.GetChildAgentCount(); | ||
987 | |||
988 | if (agentsInScene > 21) | ||
989 | { | ||
990 | if (m_update_entities == 1) | ||
991 | { | ||
992 | m_update_entities = 5; | ||
993 | StatsReporter.SetUpdateMS(6000); | ||
994 | } | ||
995 | } | ||
996 | else | ||
997 | { | ||
998 | if (m_update_entities == 5) | ||
999 | { | ||
1000 | m_update_entities = 1; | ||
1001 | StatsReporter.SetUpdateMS(3000); | ||
1002 | } | ||
1003 | } | ||
1004 | 984 | ||
1005 | frameMS = Environment.TickCount; | 985 | frameMS = Environment.TickCount; |
1006 | try | 986 | try |
@@ -1013,30 +993,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
1013 | m_frame = 0; | 993 | m_frame = 0; |
1014 | 994 | ||
1015 | otherMS = Environment.TickCount; | 995 | otherMS = Environment.TickCount; |
1016 | // run through all entities looking for updates (slow) | ||
1017 | if (m_frame % m_update_entities == 0) | ||
1018 | { | ||
1019 | /* // Adam Experimental | ||
1020 | if (m_updateEntitiesThread == null) | ||
1021 | { | ||
1022 | m_updateEntitiesThread = new Thread(m_sceneGraph.UpdateEntities); | ||
1023 | |||
1024 | ThreadTracker.Add(m_updateEntitiesThread); | ||
1025 | } | ||
1026 | |||
1027 | if (m_updateEntitiesThread.ThreadState == ThreadState.Stopped) | ||
1028 | m_updateEntitiesThread.Start(); | ||
1029 | */ | ||
1030 | 996 | ||
1031 | m_sceneGraph.UpdateEntities(); | 997 | // Check if any objects have reached their targets |
1032 | } | 998 | CheckAtTargets(); |
999 | |||
1000 | // Update SceneObjectGroups that have scheduled themselves for updates | ||
1001 | // Objects queue their updates onto all scene presences | ||
1002 | if (m_frame % m_update_objects == 0) | ||
1003 | m_sceneGraph.UpdateObjectGroups(); | ||
1033 | 1004 | ||
1034 | // run through entities that have scheduled themselves for | 1005 | // Run through all ScenePresences looking for updates |
1035 | // updates looking for updates(faster) | 1006 | // Presence updates and queued object updates for each presence are sent to clients |
1036 | if (m_frame % m_update_entitiesquick == 0) | ||
1037 | m_sceneGraph.ProcessUpdates(); | ||
1038 | |||
1039 | // Run through scenepresences looking for updates | ||
1040 | if (m_frame % m_update_presences == 0) | 1007 | if (m_frame % m_update_presences == 0) |
1041 | m_sceneGraph.UpdatePresences(); | 1008 | m_sceneGraph.UpdatePresences(); |
1042 | 1009 | ||
@@ -1140,6 +1107,31 @@ namespace OpenSim.Region.Framework.Scenes | |||
1140 | } | 1107 | } |
1141 | } | 1108 | } |
1142 | 1109 | ||
1110 | |||
1111 | public void AddGroupTarget(SceneObjectGroup grp) | ||
1112 | { | ||
1113 | lock(m_groupsWithTargets) | ||
1114 | m_groupsWithTargets[grp.UUID] = grp; | ||
1115 | } | ||
1116 | |||
1117 | public void RemoveGroupTarget(SceneObjectGroup grp) | ||
1118 | { | ||
1119 | lock(m_groupsWithTargets) | ||
1120 | m_groupsWithTargets.Remove(grp.UUID); | ||
1121 | } | ||
1122 | |||
1123 | private void CheckAtTargets() | ||
1124 | { | ||
1125 | lock (m_groupsWithTargets) | ||
1126 | { | ||
1127 | foreach (KeyValuePair<UUID, SceneObjectGroup> kvp in m_groupsWithTargets) | ||
1128 | { | ||
1129 | kvp.Value.checkAtTargets(); | ||
1130 | } | ||
1131 | } | ||
1132 | } | ||
1133 | |||
1134 | |||
1143 | /// <summary> | 1135 | /// <summary> |
1144 | /// Send out simstats data to all clients | 1136 | /// Send out simstats data to all clients |
1145 | /// </summary> | 1137 | /// </summary> |
@@ -1186,10 +1178,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1186 | if (!m_backingup) | 1178 | if (!m_backingup) |
1187 | { | 1179 | { |
1188 | m_backingup = true; | 1180 | m_backingup = true; |
1189 | Thread backupthread = new Thread(Backup); | 1181 | |
1190 | backupthread.Name = "BackupWriter"; | 1182 | System.ComponentModel.BackgroundWorker backupWorker = new System.ComponentModel.BackgroundWorker(); |
1191 | backupthread.IsBackground = true; | 1183 | backupWorker.DoWork += delegate(object sender, System.ComponentModel.DoWorkEventArgs e) { Backup(); }; |
1192 | backupthread.Start(); | 1184 | backupWorker.RunWorkerAsync(); |
1193 | } | 1185 | } |
1194 | } | 1186 | } |
1195 | 1187 | ||
@@ -2436,6 +2428,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2436 | /// <param name="client"></param> | 2428 | /// <param name="client"></param> |
2437 | public override void AddNewClient(IClientAPI client) | 2429 | public override void AddNewClient(IClientAPI client) |
2438 | { | 2430 | { |
2431 | ClientManager.Add(client); | ||
2432 | |||
2439 | CheckHeartbeat(); | 2433 | CheckHeartbeat(); |
2440 | SubscribeToClientEvents(client); | 2434 | SubscribeToClientEvents(client); |
2441 | ScenePresence presence; | 2435 | ScenePresence presence; |
@@ -2645,6 +2639,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2645 | public virtual void SubscribeToClientNetworkEvents(IClientAPI client) | 2639 | public virtual void SubscribeToClientNetworkEvents(IClientAPI client) |
2646 | { | 2640 | { |
2647 | client.OnNetworkStatsUpdate += StatsReporter.AddPacketsStats; | 2641 | client.OnNetworkStatsUpdate += StatsReporter.AddPacketsStats; |
2642 | client.OnViewerEffect += ProcessViewerEffect; | ||
2648 | } | 2643 | } |
2649 | 2644 | ||
2650 | protected virtual void UnsubscribeToClientEvents(IClientAPI client) | 2645 | protected virtual void UnsubscribeToClientEvents(IClientAPI client) |
@@ -2799,11 +2794,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2799 | public virtual void UnSubscribeToClientNetworkEvents(IClientAPI client) | 2794 | public virtual void UnSubscribeToClientNetworkEvents(IClientAPI client) |
2800 | { | 2795 | { |
2801 | client.OnNetworkStatsUpdate -= StatsReporter.AddPacketsStats; | 2796 | client.OnNetworkStatsUpdate -= StatsReporter.AddPacketsStats; |
2797 | client.OnViewerEffect -= ProcessViewerEffect; | ||
2802 | } | 2798 | } |
2803 | 2799 | ||
2804 | |||
2805 | |||
2806 | |||
2807 | /// <summary> | 2800 | /// <summary> |
2808 | /// Teleport an avatar to their home region | 2801 | /// Teleport an avatar to their home region |
2809 | /// </summary> | 2802 | /// </summary> |
@@ -3076,7 +3069,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
3076 | agentTransactions.RemoveAgentAssetTransactions(agentID); | 3069 | agentTransactions.RemoveAgentAssetTransactions(agentID); |
3077 | } | 3070 | } |
3078 | 3071 | ||
3072 | // Remove the avatar from the scene | ||
3079 | m_sceneGraph.RemoveScenePresence(agentID); | 3073 | m_sceneGraph.RemoveScenePresence(agentID); |
3074 | ClientManager.Remove(agentID); | ||
3080 | 3075 | ||
3081 | try | 3076 | try |
3082 | { | 3077 | { |
@@ -3126,16 +3121,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3126 | } | 3121 | } |
3127 | 3122 | ||
3128 | /// <summary> | 3123 | /// <summary> |
3129 | /// Closes all endpoints with the circuitcode provided. | ||
3130 | /// </summary> | ||
3131 | /// <param name="circuitcode">Circuit Code of the endpoint to close</param> | ||
3132 | public override void CloseAllAgents(uint circuitcode) | ||
3133 | { | ||
3134 | // Called by ClientView to kill all circuit codes | ||
3135 | ClientManager.CloseAllAgents(circuitcode); | ||
3136 | } | ||
3137 | |||
3138 | /// <summary> | ||
3139 | /// Inform all other ScenePresences on this Scene that someone else has changed position on the minimap. | 3124 | /// Inform all other ScenePresences on this Scene that someone else has changed position on the minimap. |
3140 | /// </summary> | 3125 | /// </summary> |
3141 | public void NotifyMyCoarseLocationChange() | 3126 | public void NotifyMyCoarseLocationChange() |
@@ -3456,7 +3441,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3456 | loggingOffUser.ControllingClient.Kick(message); | 3441 | loggingOffUser.ControllingClient.Kick(message); |
3457 | // Give them a second to receive the message! | 3442 | // Give them a second to receive the message! |
3458 | Thread.Sleep(1000); | 3443 | Thread.Sleep(1000); |
3459 | loggingOffUser.ControllingClient.Close(true); | 3444 | loggingOffUser.ControllingClient.Close(); |
3460 | } | 3445 | } |
3461 | else | 3446 | else |
3462 | { | 3447 | { |
@@ -3627,7 +3612,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3627 | presence.ControllingClient.SendShutdownConnectionNotice(); | 3612 | presence.ControllingClient.SendShutdownConnectionNotice(); |
3628 | } | 3613 | } |
3629 | 3614 | ||
3630 | presence.ControllingClient.Close(true); | 3615 | presence.ControllingClient.Close(); |
3631 | return true; | 3616 | return true; |
3632 | } | 3617 | } |
3633 | 3618 | ||
diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs index 0ac4ed4..cf5c3c8 100644 --- a/OpenSim/Region/Framework/Scenes/SceneBase.cs +++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs | |||
@@ -196,8 +196,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
196 | /// <param name="agentID"></param> | 196 | /// <param name="agentID"></param> |
197 | public abstract void RemoveClient(UUID agentID); | 197 | public abstract void RemoveClient(UUID agentID); |
198 | 198 | ||
199 | public abstract void CloseAllAgents(uint circuitcode); | ||
200 | |||
201 | #endregion | 199 | #endregion |
202 | 200 | ||
203 | /// <summary> | 201 | /// <summary> |
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 54ac792..9cd2247 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs | |||
@@ -77,7 +77,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
77 | 77 | ||
78 | protected RegionInfo m_regInfo; | 78 | protected RegionInfo m_regInfo; |
79 | protected Scene m_parentScene; | 79 | protected Scene m_parentScene; |
80 | protected Dictionary<UUID, EntityBase> m_updateList = new Dictionary<UUID, EntityBase>(); | 80 | protected Dictionary<UUID, SceneObjectGroup> m_updateList = new Dictionary<UUID, SceneObjectGroup>(); |
81 | protected int m_numRootAgents = 0; | 81 | protected int m_numRootAgents = 0; |
82 | protected int m_numPrim = 0; | 82 | protected int m_numPrim = 0; |
83 | protected int m_numChildAgents = 0; | 83 | protected int m_numChildAgents = 0; |
@@ -155,16 +155,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
155 | } | 155 | } |
156 | } | 156 | } |
157 | 157 | ||
158 | protected internal void UpdateEntities() | ||
159 | { | ||
160 | List<EntityBase> updateEntities = GetEntities(); | ||
161 | |||
162 | foreach (EntityBase entity in updateEntities) | ||
163 | { | ||
164 | entity.Update(); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | protected internal void UpdatePresences() | 158 | protected internal void UpdatePresences() |
169 | { | 159 | { |
170 | List<ScenePresence> updateScenePresences = GetScenePresences(); | 160 | List<ScenePresence> updateScenePresences = GetScenePresences(); |
@@ -365,12 +355,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
365 | } | 355 | } |
366 | 356 | ||
367 | /// <summary> | 357 | /// <summary> |
368 | /// Add an entity to the list of prims to process on the next update | 358 | /// Add an object to the list of prims to process on the next update |
369 | /// </summary> | 359 | /// </summary> |
370 | /// <param name="obj"> | 360 | /// <param name="obj"> |
371 | /// A <see cref="EntityBase"/> | 361 | /// A <see cref="SceneObjectGroup"/> |
372 | /// </param> | 362 | /// </param> |
373 | protected internal void AddToUpdateList(EntityBase obj) | 363 | protected internal void AddToUpdateList(SceneObjectGroup obj) |
374 | { | 364 | { |
375 | lock (m_updateList) | 365 | lock (m_updateList) |
376 | { | 366 | { |
@@ -381,18 +371,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
381 | /// <summary> | 371 | /// <summary> |
382 | /// Process all pending updates | 372 | /// Process all pending updates |
383 | /// </summary> | 373 | /// </summary> |
384 | protected internal void ProcessUpdates() | 374 | protected internal void UpdateObjectGroups() |
385 | { | 375 | { |
386 | Dictionary<UUID, EntityBase> updates; | 376 | Dictionary<UUID, SceneObjectGroup> updates; |
387 | // Some updates add more updates to the updateList. | 377 | // Some updates add more updates to the updateList. |
388 | // Get the current list of updates and clear the list before iterating | 378 | // Get the current list of updates and clear the list before iterating |
389 | lock (m_updateList) | 379 | lock (m_updateList) |
390 | { | 380 | { |
391 | updates = new Dictionary<UUID, EntityBase>(m_updateList); | 381 | updates = new Dictionary<UUID, SceneObjectGroup>(m_updateList); |
392 | m_updateList.Clear(); | 382 | m_updateList.Clear(); |
393 | } | 383 | } |
394 | // Go through all timers | 384 | // Go through all updates |
395 | foreach (KeyValuePair<UUID, EntityBase> kvp in updates) | 385 | foreach (KeyValuePair<UUID, SceneObjectGroup> kvp in updates) |
396 | { | 386 | { |
397 | // Don't abort the whole update if one entity happens to give us an exception. | 387 | // Don't abort the whole update if one entity happens to give us an exception. |
398 | try | 388 | try |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 6a10618..d4cef7d 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -1234,6 +1234,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1234 | { | 1234 | { |
1235 | lock (m_targets) | 1235 | lock (m_targets) |
1236 | m_targets.Clear(); | 1236 | m_targets.Clear(); |
1237 | m_scene.RemoveGroupTarget(this); | ||
1237 | } | 1238 | } |
1238 | 1239 | ||
1239 | ScheduleGroupForFullUpdate(); | 1240 | ScheduleGroupForFullUpdate(); |
@@ -1864,12 +1865,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1864 | m_rootPart.UpdateFlag = 1; | 1865 | m_rootPart.UpdateFlag = 1; |
1865 | lastPhysGroupPos = AbsolutePosition; | 1866 | lastPhysGroupPos = AbsolutePosition; |
1866 | } | 1867 | } |
1867 | //foreach (SceneObjectPart part in m_parts.Values) | ||
1868 | //{ | ||
1869 | //if (part.UpdateFlag == 0) part.UpdateFlag = 1; | ||
1870 | //} | ||
1871 | |||
1872 | checkAtTargets(); | ||
1873 | 1868 | ||
1874 | if (UsePhysics && ((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1) | 1869 | if (UsePhysics && ((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1) |
1875 | || (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1) | 1870 | || (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1) |
@@ -3114,6 +3109,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3114 | { | 3109 | { |
3115 | m_targets.Add(handle, waypoint); | 3110 | m_targets.Add(handle, waypoint); |
3116 | } | 3111 | } |
3112 | m_scene.AddGroupTarget(this); | ||
3117 | return (int)handle; | 3113 | return (int)handle; |
3118 | } | 3114 | } |
3119 | 3115 | ||
@@ -3121,12 +3117,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
3121 | { | 3117 | { |
3122 | lock (m_targets) | 3118 | lock (m_targets) |
3123 | { | 3119 | { |
3124 | if (m_targets.ContainsKey((uint)handle)) | 3120 | m_targets.Remove((uint)handle); |
3125 | m_targets.Remove((uint)handle); | 3121 | if (m_targets.Count == 0) |
3122 | m_scene.RemoveGroupTarget(this); | ||
3126 | } | 3123 | } |
3127 | } | 3124 | } |
3128 | 3125 | ||
3129 | private void checkAtTargets() | 3126 | public void checkAtTargets() |
3130 | { | 3127 | { |
3131 | if (m_scriptListens_atTarget || m_scriptListens_notAtTarget) | 3128 | if (m_scriptListens_atTarget || m_scriptListens_notAtTarget) |
3132 | { | 3129 | { |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneBaseTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneBaseTests.cs index 5c9e66f..8230f32 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneBaseTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneBaseTests.cs | |||
@@ -61,11 +61,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
61 | throw new NotImplementedException(); | 61 | throw new NotImplementedException(); |
62 | } | 62 | } |
63 | 63 | ||
64 | public override void CloseAllAgents(uint circuitcode) | ||
65 | { | ||
66 | throw new NotImplementedException(); | ||
67 | } | ||
68 | |||
69 | public override void OtherRegionUp(GridRegion otherRegion) | 64 | public override void OtherRegionUp(GridRegion otherRegion) |
70 | { | 65 | { |
71 | throw new NotImplementedException(); | 66 | throw new NotImplementedException(); |
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/IRCStackModule.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/IRCStackModule.cs index 4b199ac..4c2a4b9 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/IRCStackModule.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/IRCStackModule.cs | |||
@@ -64,7 +64,6 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView | |||
64 | void user_OnIRCReady(IRCClientView cv) | 64 | void user_OnIRCReady(IRCClientView cv) |
65 | { | 65 | { |
66 | m_log.Info("[IRCd] Adding user..."); | 66 | m_log.Info("[IRCd] Adding user..."); |
67 | m_scene.ClientManager.Add(cv.CircuitCode, cv); | ||
68 | cv.Start(); | 67 | cv.Start(); |
69 | m_log.Info("[IRCd] Added user to Scene"); | 68 | m_log.Info("[IRCd] Added user to Scene"); |
70 | } | 69 | } |
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 4364627..a8acf0d 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs | |||
@@ -634,6 +634,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server | |||
634 | { | 634 | { |
635 | get { return (uint)Util.RandomClass.Next(0,int.MaxValue); } | 635 | get { return (uint)Util.RandomClass.Next(0,int.MaxValue); } |
636 | } | 636 | } |
637 | |||
638 | public IPEndPoint RemoteEndPoint | ||
639 | { | ||
640 | get { return (IPEndPoint)m_client.Client.RemoteEndPoint; } | ||
641 | } | ||
642 | |||
637 | #pragma warning disable 67 | 643 | #pragma warning disable 67 |
638 | public event GenericMessage OnGenericMessage; | 644 | public event GenericMessage OnGenericMessage; |
639 | public event ImprovedInstantMessage OnInstantMessage; | 645 | public event ImprovedInstantMessage OnInstantMessage; |
@@ -843,7 +849,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server | |||
843 | 849 | ||
844 | } | 850 | } |
845 | 851 | ||
846 | public void Close(bool ShutdownCircuit) | 852 | public void Close() |
847 | { | 853 | { |
848 | Disconnect(); | 854 | Disconnect(); |
849 | } | 855 | } |
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs index d6dacbc..b6513e2 100644 --- a/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs +++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs | |||
@@ -183,8 +183,9 @@ namespace OpenSim.Region.OptionalModules.ContentManagement | |||
183 | public virtual void HideFromAll() | 183 | public virtual void HideFromAll() |
184 | { | 184 | { |
185 | foreach (SceneObjectPart part in m_Entity.Children.Values) | 185 | foreach (SceneObjectPart part in m_Entity.Children.Values) |
186 | m_Entity.Scene.ClientManager.ForEachClient(delegate(IClientAPI controller) | 186 | m_Entity.Scene.ClientManager.ForEach( |
187 | { controller.SendKillObject(m_Entity.RegionHandle, part.LocalId); } | 187 | delegate(IClientAPI controller) |
188 | { controller.SendKillObject(m_Entity.RegionHandle, part.LocalId); } | ||
188 | ); | 189 | ); |
189 | } | 190 | } |
190 | 191 | ||
@@ -201,8 +202,9 @@ namespace OpenSim.Region.OptionalModules.ContentManagement | |||
201 | 202 | ||
202 | public void SendFullUpdateToAll() | 203 | public void SendFullUpdateToAll() |
203 | { | 204 | { |
204 | m_Entity.Scene.ClientManager.ForEachClient(delegate(IClientAPI controller) | 205 | m_Entity.Scene.ClientManager.ForEach( |
205 | { m_Entity.SendFullUpdateToClient(controller); } | 206 | delegate(IClientAPI controller) |
207 | { m_Entity.SendFullUpdateToClient(controller); } | ||
206 | ); | 208 | ); |
207 | } | 209 | } |
208 | 210 | ||
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index ac8b98c..f7c63ac 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs | |||
@@ -825,7 +825,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
825 | { | 825 | { |
826 | } | 826 | } |
827 | 827 | ||
828 | public void Close(bool ShutdownCircuit) | 828 | public void Close() |
829 | { | 829 | { |
830 | } | 830 | } |
831 | 831 | ||
@@ -838,11 +838,21 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
838 | } | 838 | } |
839 | 839 | ||
840 | private uint m_circuitCode; | 840 | private uint m_circuitCode; |
841 | private IPEndPoint m_remoteEndPoint; | ||
841 | 842 | ||
842 | public uint CircuitCode | 843 | public uint CircuitCode |
843 | { | 844 | { |
844 | get { return m_circuitCode; } | 845 | get { return m_circuitCode; } |
845 | set { m_circuitCode = value; } | 846 | set |
847 | { | ||
848 | m_circuitCode = value; | ||
849 | m_remoteEndPoint = new IPEndPoint(IPAddress.Loopback, (ushort)m_circuitCode); | ||
850 | } | ||
851 | } | ||
852 | |||
853 | public IPEndPoint RemoteEndPoint | ||
854 | { | ||
855 | get { return m_remoteEndPoint; } | ||
846 | } | 856 | } |
847 | 857 | ||
848 | public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message) | 858 | public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message) |
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index 30a2675..41a6255 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs | |||
@@ -155,7 +155,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
155 | NPCAvatar npcAvatar = new NPCAvatar(p_firstname, p_lastname, p_position, p_scene); | 155 | NPCAvatar npcAvatar = new NPCAvatar(p_firstname, p_lastname, p_position, p_scene); |
156 | npcAvatar.CircuitCode = (uint) Util.RandomClass.Next(0, int.MaxValue); | 156 | npcAvatar.CircuitCode = (uint) Util.RandomClass.Next(0, int.MaxValue); |
157 | 157 | ||
158 | p_scene.ClientManager.Add(npcAvatar.CircuitCode, npcAvatar); | ||
159 | p_scene.AddNewClient(npcAvatar); | 158 | p_scene.AddNewClient(npcAvatar); |
160 | 159 | ||
161 | ScenePresence sp; | 160 | ScenePresence sp; |
diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs index a283840..47ce615 100644 --- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs +++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs | |||
@@ -69,7 +69,7 @@ namespace PrimMesher | |||
69 | 69 | ||
70 | public Quat Identity() | 70 | public Quat Identity() |
71 | { | 71 | { |
72 | return new Quat(0.0f, 0.0f, 0.0f, 1.1f); | 72 | return new Quat(0.0f, 0.0f, 0.0f, 1.0f); |
73 | } | 73 | } |
74 | 74 | ||
75 | public float Length() | 75 | public float Length() |
diff --git a/OpenSim/Services/AssetService/AssetService.cs b/OpenSim/Services/AssetService/AssetService.cs index ebfd47a..df33db2 100644 --- a/OpenSim/Services/AssetService/AssetService.cs +++ b/OpenSim/Services/AssetService/AssetService.cs | |||
@@ -64,12 +64,17 @@ namespace OpenSim.Services.AssetService | |||
64 | string loaderArgs = assetConfig.GetString("AssetLoaderArgs", | 64 | string loaderArgs = assetConfig.GetString("AssetLoaderArgs", |
65 | String.Empty); | 65 | String.Empty); |
66 | 66 | ||
67 | m_log.InfoFormat("[ASSET]: Loading default asset set from {0}", loaderArgs); | 67 | bool assetLoaderEnabled = assetConfig.GetBoolean("AssetLoaderEnabled", true); |
68 | m_AssetLoader.ForEachDefaultXmlAsset(loaderArgs, | 68 | |
69 | delegate(AssetBase a) | 69 | if (assetLoaderEnabled) |
70 | { | 70 | { |
71 | Store(a); | 71 | m_log.InfoFormat("[ASSET]: Loading default asset set from {0}", loaderArgs); |
72 | }); | 72 | m_AssetLoader.ForEachDefaultXmlAsset(loaderArgs, |
73 | delegate(AssetBase a) | ||
74 | { | ||
75 | Store(a); | ||
76 | }); | ||
77 | } | ||
73 | 78 | ||
74 | m_log.Info("[ASSET CONNECTOR]: Local asset service enabled"); | 79 | m_log.Info("[ASSET CONNECTOR]: Local asset service enabled"); |
75 | } | 80 | } |
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 2b54890..5c838c5 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs | |||
@@ -393,6 +393,11 @@ namespace OpenSim.Tests.Common.Mock | |||
393 | set { m_circuitCode = value; } | 393 | set { m_circuitCode = value; } |
394 | } | 394 | } |
395 | 395 | ||
396 | public IPEndPoint RemoteEndPoint | ||
397 | { | ||
398 | get { return new IPEndPoint(IPAddress.Loopback, (ushort)m_circuitCode); } | ||
399 | } | ||
400 | |||
396 | /// <summary> | 401 | /// <summary> |
397 | /// Constructor | 402 | /// Constructor |
398 | /// </summary> | 403 | /// </summary> |
@@ -865,7 +870,7 @@ namespace OpenSim.Tests.Common.Mock | |||
865 | { | 870 | { |
866 | } | 871 | } |
867 | 872 | ||
868 | public void Close(bool ShutdownCircuit) | 873 | public void Close() |
869 | { | 874 | { |
870 | m_scene.RemoveClient(AgentId); | 875 | m_scene.RemoveClient(AgentId); |
871 | } | 876 | } |