diff options
63 files changed, 2132 insertions, 1874 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/Data/MySQL/MySQLRegionData.cs b/OpenSim/Data/MySQL/MySQLRegionData.cs index 3b561d1..f514076 100644 --- a/OpenSim/Data/MySQL/MySQLRegionData.cs +++ b/OpenSim/Data/MySQL/MySQLRegionData.cs | |||
@@ -151,7 +151,10 @@ namespace OpenSim.Data.MySQL | |||
151 | 151 | ||
152 | DataTable schemaTable = result.GetSchemaTable(); | 152 | DataTable schemaTable = result.GetSchemaTable(); |
153 | foreach (DataRow row in schemaTable.Rows) | 153 | foreach (DataRow row in schemaTable.Rows) |
154 | m_ColumnNames.Add(row["ColumnName"].ToString()); | 154 | { |
155 | if (row["ColumnName"] != null) | ||
156 | m_ColumnNames.Add(row["ColumnName"].ToString()); | ||
157 | } | ||
155 | } | 158 | } |
156 | 159 | ||
157 | foreach (string s in m_ColumnNames) | 160 | foreach (string s in m_ColumnNames) |
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 5877779..b53a2fb 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs | |||
@@ -31,6 +31,7 @@ using OpenMetaverse; | |||
31 | using OpenMetaverse.Imaging; | 31 | using OpenMetaverse.Imaging; |
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenSim.Region.Framework.Interfaces; | 33 | using OpenSim.Region.Framework.Interfaces; |
34 | using OpenSim.Region.Framework.Scenes.Hypergrid; | ||
34 | using OpenSim.Services.Interfaces; | 35 | using OpenSim.Services.Interfaces; |
35 | using log4net; | 36 | using log4net; |
36 | using System.Reflection; | 37 | using System.Reflection; |
@@ -54,6 +55,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
54 | public UUID TextureID; | 55 | public UUID TextureID; |
55 | public IJ2KDecoder J2KDecoder; | 56 | public IJ2KDecoder J2KDecoder; |
56 | public IAssetService AssetService; | 57 | public IAssetService AssetService; |
58 | public UUID AgentID; | ||
59 | public IHyperAssetService HyperAssets; | ||
57 | public OpenJPEG.J2KLayerInfo[] Layers; | 60 | public OpenJPEG.J2KLayerInfo[] Layers; |
58 | public bool IsDecoded; | 61 | public bool IsDecoded; |
59 | public bool HasAsset; | 62 | public bool HasAsset; |
@@ -72,14 +75,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
72 | m_imageManager = imageManager; | 75 | m_imageManager = imageManager; |
73 | } | 76 | } |
74 | 77 | ||
75 | 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) | ||
76 | { | 87 | { |
77 | if (client == null) | 88 | packetsSent = 0; |
78 | return false; | ||
79 | 89 | ||
80 | if (m_currentPacket <= m_stopPacket) | 90 | if (m_currentPacket <= m_stopPacket) |
81 | { | 91 | { |
82 | int count = 0; | ||
83 | bool sendMore = true; | 92 | bool sendMore = true; |
84 | 93 | ||
85 | if (!m_sentInfo || (m_currentPacket == 0)) | 94 | if (!m_sentInfo || (m_currentPacket == 0)) |
@@ -88,25 +97,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
88 | 97 | ||
89 | m_sentInfo = true; | 98 | m_sentInfo = true; |
90 | ++m_currentPacket; | 99 | ++m_currentPacket; |
91 | ++count; | 100 | ++packetsSent; |
92 | } | 101 | } |
93 | if (m_currentPacket < 2) | 102 | if (m_currentPacket < 2) |
94 | { | 103 | { |
95 | m_currentPacket = 2; | 104 | m_currentPacket = 2; |
96 | } | 105 | } |
97 | 106 | ||
98 | while (sendMore && count < maxpack && m_currentPacket <= m_stopPacket) | 107 | while (sendMore && packetsSent < packetsToSend && m_currentPacket <= m_stopPacket) |
99 | { | 108 | { |
100 | sendMore = SendPacket(client); | 109 | sendMore = SendPacket(client); |
101 | ++m_currentPacket; | 110 | ++m_currentPacket; |
102 | ++count; | 111 | ++packetsSent; |
103 | } | 112 | } |
104 | |||
105 | if (m_currentPacket > m_stopPacket) | ||
106 | return true; | ||
107 | } | 113 | } |
108 | 114 | ||
109 | return false; | 115 | return (m_currentPacket > m_stopPacket); |
110 | } | 116 | } |
111 | 117 | ||
112 | public void RunUpdate() | 118 | public void RunUpdate() |
@@ -370,6 +376,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
370 | UUID assetID = UUID.Zero; | 376 | UUID assetID = UUID.Zero; |
371 | if (asset != null) | 377 | if (asset != null) |
372 | assetID = asset.FullID; | 378 | assetID = asset.FullID; |
379 | else if ((HyperAssets != null) && (sender != HyperAssets)) | ||
380 | { | ||
381 | // Try the user's inventory, but only if it's different from the regions' | ||
382 | string userAssets = HyperAssets.GetUserAssetServer(AgentID); | ||
383 | if ((userAssets != string.Empty) && (userAssets != HyperAssets.GetSimAssetServer())) | ||
384 | { | ||
385 | m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", id); | ||
386 | AssetService.Get(userAssets + "/" + id, HyperAssets, AssetReceived); | ||
387 | return; | ||
388 | } | ||
389 | } | ||
373 | 390 | ||
374 | AssetDataCallback(assetID, asset); | 391 | AssetDataCallback(assetID, asset); |
375 | 392 | ||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 84e705a..8487adc 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | |||
@@ -43,6 +43,7 @@ using OpenSim.Framework.Communications.Cache; | |||
43 | using OpenSim.Framework.Statistics; | 43 | using OpenSim.Framework.Statistics; |
44 | using OpenSim.Region.Framework.Interfaces; | 44 | using OpenSim.Region.Framework.Interfaces; |
45 | using OpenSim.Region.Framework.Scenes; | 45 | using OpenSim.Region.Framework.Scenes; |
46 | using OpenSim.Region.Framework.Scenes.Hypergrid; | ||
46 | using OpenSim.Services.Interfaces; | 47 | using OpenSim.Services.Interfaces; |
47 | using Timer=System.Timers.Timer; | 48 | using Timer=System.Timers.Timer; |
48 | using AssetLandmark = OpenSim.Framework.AssetLandmark; | 49 | using AssetLandmark = OpenSim.Framework.AssetLandmark; |
@@ -58,6 +59,209 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
58 | /// </summary> | 59 | /// </summary> |
59 | public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientIPEndpoint, IStatsCollector | 60 | public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientIPEndpoint, IStatsCollector |
60 | { | 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 | |||
61 | // LLClientView Only | 265 | // LLClientView Only |
62 | public delegate void BinaryGenericMessage(Object sender, string method, byte[][] args); | 266 | public delegate void BinaryGenericMessage(Object sender, string method, byte[][] args); |
63 | 267 | ||
@@ -110,15 +314,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
110 | protected int m_primFullUpdatesPerPacket = 14; | 314 | protected int m_primFullUpdatesPerPacket = 14; |
111 | protected int m_primTerseUpdateRate = 10; | 315 | protected int m_primTerseUpdateRate = 10; |
112 | protected int m_primFullUpdateRate = 14; | 316 | protected int m_primFullUpdateRate = 14; |
113 | protected int m_textureSendLimit = 20; | ||
114 | protected int m_textureDataLimit = 10; | ||
115 | protected int m_avatarTerseUpdateRate = 50; | 317 | protected int m_avatarTerseUpdateRate = 50; |
116 | protected int m_avatarTerseUpdatesPerPacket = 5; | 318 | protected int m_avatarTerseUpdatesPerPacket = 5; |
117 | 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; | ||
118 | protected IAssetService m_assetService; | 322 | protected IAssetService m_assetService; |
323 | private IHyperAssetService m_hyperAssets; | ||
324 | |||
325 | |||
326 | #endregion Class Members | ||
119 | 327 | ||
120 | #region Properties | 328 | #region Properties |
121 | 329 | ||
330 | public LLUDPClient UDPClient { get { return m_udpClient; } } | ||
331 | public IPEndPoint RemoteEndPoint { get { return m_udpClient.RemoteEndPoint; } } | ||
122 | public UUID SecureSessionId { get { return m_secureSessionId; } } | 332 | public UUID SecureSessionId { get { return m_secureSessionId; } } |
123 | public IScene Scene { get { return m_scene; } } | 333 | public IScene Scene { get { return m_scene; } } |
124 | public UUID SessionId { get { return m_sessionId; } } | 334 | public UUID SessionId { get { return m_sessionId; } } |
@@ -170,6 +380,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
170 | 380 | ||
171 | m_scene = scene; | 381 | m_scene = scene; |
172 | m_assetService = m_scene.RequestModuleInterface<IAssetService>(); | 382 | m_assetService = m_scene.RequestModuleInterface<IAssetService>(); |
383 | m_hyperAssets = m_scene.RequestModuleInterface<IHyperAssetService>(); | ||
173 | m_GroupsModule = scene.RequestModuleInterface<IGroupsModule>(); | 384 | m_GroupsModule = scene.RequestModuleInterface<IGroupsModule>(); |
174 | m_imageManager = new LLImageManager(this, m_assetService, Scene.RequestModuleInterface<IJ2KDecoder>()); | 385 | m_imageManager = new LLImageManager(this, m_assetService, Scene.RequestModuleInterface<IJ2KDecoder>()); |
175 | m_channelVersion = Utils.StringToBytes(scene.GetSimulatorVersion()); | 386 | m_channelVersion = Utils.StringToBytes(scene.GetSimulatorVersion()); |
@@ -198,51 +409,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
198 | #region Client Methods | 409 | #region Client Methods |
199 | 410 | ||
200 | /// <summary> | 411 | /// <summary> |
201 | /// Close down the client view. This *must* be the last method called, since the last # | 412 | /// Shut down the client view |
202 | /// statement of CloseCleanup() aborts the thread. | ||
203 | /// </summary> | 413 | /// </summary> |
204 | /// <param name="shutdownCircuit"></param> | 414 | public void Close() |
205 | public void Close(bool shutdownCircuit) | ||
206 | { | 415 | { |
207 | m_log.DebugFormat( | 416 | m_log.DebugFormat( |
208 | "[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}", |
209 | shutdownCircuit, Name, m_scene.RegionInfo.RegionName); | 418 | Name, m_scene.RegionInfo.RegionName); |
419 | |||
420 | // Send the STOP packet | ||
421 | DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); | ||
422 | OutPacket(disable, ThrottleOutPacketType.Unknown); | ||
423 | |||
424 | IsActive = false; | ||
210 | 425 | ||
426 | // Shutdown the image manager | ||
211 | if (m_imageManager != null) | 427 | if (m_imageManager != null) |
212 | m_imageManager.Close(); | 428 | m_imageManager.Close(); |
213 | 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 | ||
214 | if (m_udpServer != null) | 435 | if (m_udpServer != null) |
215 | m_udpServer.Flush(); | 436 | m_udpServer.Flush(m_udpClient); |
216 | |||
217 | // raise an event on the packet server to Shutdown the circuit | ||
218 | // Now, if we raise the event then the packet server will call this method itself, so don't try cleanup | ||
219 | // here otherwise we'll end up calling it twice. | ||
220 | // FIXME: In truth, I might be wrong but this whole business of calling this method twice (with different args) looks | ||
221 | // horribly tangly. Hopefully it should be possible to greatly simplify it. | ||
222 | if (shutdownCircuit) | ||
223 | { | ||
224 | if (OnConnectionClosed != null) | ||
225 | OnConnectionClosed(this); | ||
226 | } | ||
227 | else | ||
228 | { | ||
229 | CloseCleanup(shutdownCircuit); | ||
230 | } | ||
231 | } | ||
232 | 437 | ||
233 | private void CloseCleanup(bool shutdownCircuit) | 438 | // Remove ourselves from the scene |
234 | { | ||
235 | m_scene.RemoveClient(AgentId); | 439 | m_scene.RemoveClient(AgentId); |
236 | 440 | ||
237 | //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); | ||
238 | //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); | ||
239 | |||
240 | // Send the STOP packet | ||
241 | DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); | ||
242 | OutPacket(disable, ThrottleOutPacketType.Unknown); | ||
243 | |||
244 | Thread.Sleep(2000); | ||
245 | |||
246 | // 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 |
247 | if (m_avatarTerseUpdateTimer.Enabled) | 442 | if (m_avatarTerseUpdateTimer.Enabled) |
248 | lock (m_avatarTerseUpdateTimer) | 443 | lock (m_avatarTerseUpdateTimer) |
@@ -254,43 +449,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
254 | lock (m_primFullUpdateTimer) | 449 | lock (m_primFullUpdateTimer) |
255 | m_primFullUpdateTimer.Stop(); | 450 | m_primFullUpdateTimer.Stop(); |
256 | 451 | ||
257 | // This is just to give the client a reasonable chance of | ||
258 | // flushing out all it's packets. There should probably | ||
259 | // be a better mechanism here | ||
260 | |||
261 | // We can't reach into other scenes and close the connection | 452 | // We can't reach into other scenes and close the connection |
262 | // We need to do this over grid communications | 453 | // We need to do this over grid communications |
263 | //m_scene.CloseAllAgents(CircuitCode); | 454 | //m_scene.CloseAllAgents(CircuitCode); |
264 | 455 | ||
265 | // If we're not shutting down the circuit, then this is the last time we'll go here. | 456 | m_avatarTerseUpdateTimer.Dispose(); |
266 | // If we are shutting down the circuit, the UDP Server will come back here with | 457 | m_primTerseUpdateTimer.Dispose(); |
267 | // ShutDownCircuit = false | 458 | m_primFullUpdateTimer.Dispose(); |
268 | if (!(shutdownCircuit)) | ||
269 | { | ||
270 | GC.Collect(); | ||
271 | m_imageManager = null; | ||
272 | // Sends a KillPacket object, with which, the | ||
273 | // blockingqueue dequeues and sees it's a killpacket | ||
274 | // and terminates within the context of the client thread. | ||
275 | // This ensures that it's done from within the context | ||
276 | // of the client thread regardless of where Close() is called. | ||
277 | KillEndDone(); | ||
278 | } | ||
279 | |||
280 | IsActive = false; | ||
281 | |||
282 | m_avatarTerseUpdateTimer.Close(); | ||
283 | m_primTerseUpdateTimer.Close(); | ||
284 | m_primFullUpdateTimer.Close(); | ||
285 | 459 | ||
286 | //m_udpServer.OnPacketStats -= PopulateStats; | 460 | // Disable UDP handling for this client |
287 | m_udpClient.Shutdown(); | 461 | m_udpClient.Shutdown(); |
288 | 462 | ||
289 | // wait for thread stoped | 463 | //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); |
290 | // m_clientThread.Join(); | 464 | //GC.Collect(); |
291 | 465 | //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); | |
292 | // delete circuit code | ||
293 | //m_networkServer.CloseClient(this); | ||
294 | } | 466 | } |
295 | 467 | ||
296 | public void Kick(string message) | 468 | public void Kick(string message) |
@@ -412,43 +584,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
412 | return result; | 584 | return result; |
413 | } | 585 | } |
414 | 586 | ||
415 | /*protected void DebugPacket(string direction, Packet packet) | ||
416 | { | ||
417 | string info; | ||
418 | |||
419 | if (m_debugPacketLevel < 255 && packet.Type == PacketType.AgentUpdate) | ||
420 | return; | ||
421 | if (m_debugPacketLevel < 254 && packet.Type == PacketType.ViewerEffect) | ||
422 | return; | ||
423 | if (m_debugPacketLevel < 253 && ( | ||
424 | packet.Type == PacketType.CompletePingCheck || | ||
425 | packet.Type == PacketType.StartPingCheck | ||
426 | )) | ||
427 | return; | ||
428 | if (m_debugPacketLevel < 252 && packet.Type == PacketType.PacketAck) | ||
429 | return; | ||
430 | |||
431 | if (m_debugPacketLevel > 1) | ||
432 | { | ||
433 | info = packet.ToString(); | ||
434 | } | ||
435 | else | ||
436 | { | ||
437 | info = packet.Type.ToString(); | ||
438 | } | ||
439 | |||
440 | Console.WriteLine(m_circuitCode + ":" + direction + ": " + info); | ||
441 | }*/ | ||
442 | |||
443 | #endregion Packet Handling | 587 | #endregion Packet Handling |
444 | 588 | ||
445 | # region Setup | 589 | # region Setup |
446 | 590 | ||
447 | /// <summary> | 591 | public virtual void Start() |
448 | /// Starts up the timers to check the client and resend unacked packets | ||
449 | /// Adds the client to the OpenSim.Region.Framework.Scenes.Scene | ||
450 | /// </summary> | ||
451 | protected virtual void InitNewClient() | ||
452 | { | 592 | { |
453 | m_avatarTerseUpdateTimer = new Timer(m_avatarTerseUpdateRate); | 593 | m_avatarTerseUpdateTimer = new Timer(m_avatarTerseUpdateRate); |
454 | m_avatarTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates); | 594 | m_avatarTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates); |
@@ -467,262 +607,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
467 | RefreshGroupMembership(); | 607 | RefreshGroupMembership(); |
468 | } | 608 | } |
469 | 609 | ||
470 | public virtual void Start() | ||
471 | { | ||
472 | // This sets up all the timers | ||
473 | InitNewClient(); | ||
474 | } | ||
475 | |||
476 | /// <summary> | ||
477 | /// Run a user session. This method lies at the base of the entire client thread. | ||
478 | /// </summary> | ||
479 | protected void RunUserSession() | ||
480 | { | ||
481 | try | ||
482 | { | ||
483 | |||
484 | } | ||
485 | catch (Exception e) | ||
486 | { | ||
487 | if (e is ThreadAbortException) | ||
488 | throw; | ||
489 | |||
490 | if (StatsManager.SimExtraStats != null) | ||
491 | StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); | ||
492 | |||
493 | // Don't let a failure in an individual client thread crash the whole sim. | ||
494 | m_log.ErrorFormat( | ||
495 | "[CLIENT]: Client thread for {0} {1} crashed. Logging them out.", Name, AgentId); | ||
496 | m_log.Error(e.ToString()); | ||
497 | |||
498 | try | ||
499 | { | ||
500 | // Make an attempt to alert the user that their session has crashed | ||
501 | AgentAlertMessagePacket packet | ||
502 | = BuildAgentAlertPacket( | ||
503 | "Unfortunately the session for this client on the server has crashed.\n" | ||
504 | + "Any further actions taken will not be processed.\n" | ||
505 | + "Please relog", true); | ||
506 | |||
507 | m_udpServer.SendPacket(m_agentId, packet, ThrottleOutPacketType.Unknown, false); | ||
508 | |||
509 | // There may be a better way to do this. Perhaps kick? Not sure this propogates notifications to | ||
510 | // listeners yet, though. | ||
511 | Logout(this); | ||
512 | } | ||
513 | catch (Exception e2) | ||
514 | { | ||
515 | if (e2 is ThreadAbortException) | ||
516 | throw; | ||
517 | |||
518 | m_log.ErrorFormat("[CLIENT]: Further exception thrown on forced session logout. {0}", e2); | ||
519 | } | ||
520 | } | ||
521 | } | ||
522 | |||
523 | # endregion | 610 | # endregion |
524 | 611 | ||
525 | #region Events | ||
526 | |||
527 | public event GenericMessage OnGenericMessage; | ||
528 | public event BinaryGenericMessage OnBinaryGenericMessage; | ||
529 | public event Action<IClientAPI> OnLogout; | ||
530 | public event ObjectPermissions OnObjectPermissions; | ||
531 | public event Action<IClientAPI> OnConnectionClosed; | ||
532 | public event ViewerEffectEventHandler OnViewerEffect; | ||
533 | public event ImprovedInstantMessage OnInstantMessage; | ||
534 | public event ChatMessage OnChatFromClient; | ||
535 | public event TextureRequest OnRequestTexture; | ||
536 | public event RezObject OnRezObject; | ||
537 | public event DeRezObject OnDeRezObject; | ||
538 | public event ModifyTerrain OnModifyTerrain; | ||
539 | public event Action<IClientAPI> OnRegionHandShakeReply; | ||
540 | public event GenericCall2 OnRequestWearables; | ||
541 | public event SetAppearance OnSetAppearance; | ||
542 | public event AvatarNowWearing OnAvatarNowWearing; | ||
543 | public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; | ||
544 | public event RezMultipleAttachmentsFromInv OnRezMultipleAttachmentsFromInv; | ||
545 | public event UUIDNameRequest OnDetachAttachmentIntoInv; | ||
546 | public event ObjectAttach OnObjectAttach; | ||
547 | public event ObjectDeselect OnObjectDetach; | ||
548 | public event ObjectDrop OnObjectDrop; | ||
549 | public event GenericCall2 OnCompleteMovementToRegion; | ||
550 | public event UpdateAgent OnAgentUpdate; | ||
551 | public event AgentRequestSit OnAgentRequestSit; | ||
552 | public event AgentSit OnAgentSit; | ||
553 | public event AvatarPickerRequest OnAvatarPickerRequest; | ||
554 | public event StartAnim OnStartAnim; | ||
555 | public event StopAnim OnStopAnim; | ||
556 | public event Action<IClientAPI> OnRequestAvatarsData; | ||
557 | public event LinkObjects OnLinkObjects; | ||
558 | public event DelinkObjects OnDelinkObjects; | ||
559 | public event GrabObject OnGrabObject; | ||
560 | public event DeGrabObject OnDeGrabObject; | ||
561 | public event SpinStart OnSpinStart; | ||
562 | public event SpinStop OnSpinStop; | ||
563 | public event ObjectDuplicate OnObjectDuplicate; | ||
564 | public event ObjectDuplicateOnRay OnObjectDuplicateOnRay; | ||
565 | public event MoveObject OnGrabUpdate; | ||
566 | public event SpinObject OnSpinUpdate; | ||
567 | public event AddNewPrim OnAddPrim; | ||
568 | public event RequestGodlikePowers OnRequestGodlikePowers; | ||
569 | public event GodKickUser OnGodKickUser; | ||
570 | public event ObjectExtraParams OnUpdateExtraParams; | ||
571 | public event UpdateShape OnUpdatePrimShape; | ||
572 | public event ObjectRequest OnObjectRequest; | ||
573 | public event ObjectSelect OnObjectSelect; | ||
574 | public event ObjectDeselect OnObjectDeselect; | ||
575 | public event GenericCall7 OnObjectDescription; | ||
576 | public event GenericCall7 OnObjectName; | ||
577 | public event GenericCall7 OnObjectClickAction; | ||
578 | public event GenericCall7 OnObjectMaterial; | ||
579 | public event ObjectIncludeInSearch OnObjectIncludeInSearch; | ||
580 | public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; | ||
581 | public event UpdatePrimFlags OnUpdatePrimFlags; | ||
582 | public event UpdatePrimTexture OnUpdatePrimTexture; | ||
583 | public event UpdateVector OnUpdatePrimGroupPosition; | ||
584 | public event UpdateVector OnUpdatePrimSinglePosition; | ||
585 | public event UpdatePrimRotation OnUpdatePrimGroupRotation; | ||
586 | public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation; | ||
587 | public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition; | ||
588 | public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation; | ||
589 | public event UpdateVector OnUpdatePrimScale; | ||
590 | public event UpdateVector OnUpdatePrimGroupScale; | ||
591 | public event StatusChange OnChildAgentStatus; | ||
592 | public event GenericCall2 OnStopMovement; | ||
593 | public event Action<UUID> OnRemoveAvatar; | ||
594 | public event RequestMapBlocks OnRequestMapBlocks; | ||
595 | public event RequestMapName OnMapNameRequest; | ||
596 | public event TeleportLocationRequest OnTeleportLocationRequest; | ||
597 | public event TeleportLandmarkRequest OnTeleportLandmarkRequest; | ||
598 | public event DisconnectUser OnDisconnectUser; | ||
599 | public event RequestAvatarProperties OnRequestAvatarProperties; | ||
600 | public event SetAlwaysRun OnSetAlwaysRun; | ||
601 | public event FetchInventory OnAgentDataUpdateRequest; | ||
602 | public event TeleportLocationRequest OnSetStartLocationRequest; | ||
603 | public event UpdateAvatarProperties OnUpdateAvatarProperties; | ||
604 | public event CreateNewInventoryItem OnCreateNewInventoryItem; | ||
605 | public event CreateInventoryFolder OnCreateNewInventoryFolder; | ||
606 | public event UpdateInventoryFolder OnUpdateInventoryFolder; | ||
607 | public event MoveInventoryFolder OnMoveInventoryFolder; | ||
608 | public event FetchInventoryDescendents OnFetchInventoryDescendents; | ||
609 | public event PurgeInventoryDescendents OnPurgeInventoryDescendents; | ||
610 | public event FetchInventory OnFetchInventory; | ||
611 | public event RequestTaskInventory OnRequestTaskInventory; | ||
612 | public event UpdateInventoryItem OnUpdateInventoryItem; | ||
613 | public event CopyInventoryItem OnCopyInventoryItem; | ||
614 | public event MoveInventoryItem OnMoveInventoryItem; | ||
615 | public event RemoveInventoryItem OnRemoveInventoryItem; | ||
616 | public event RemoveInventoryFolder OnRemoveInventoryFolder; | ||
617 | public event UDPAssetUploadRequest OnAssetUploadRequest; | ||
618 | public event XferReceive OnXferReceive; | ||
619 | public event RequestXfer OnRequestXfer; | ||
620 | public event ConfirmXfer OnConfirmXfer; | ||
621 | public event AbortXfer OnAbortXfer; | ||
622 | public event RequestTerrain OnRequestTerrain; | ||
623 | public event RezScript OnRezScript; | ||
624 | public event UpdateTaskInventory OnUpdateTaskInventory; | ||
625 | public event MoveTaskInventory OnMoveTaskItem; | ||
626 | public event RemoveTaskInventory OnRemoveTaskItem; | ||
627 | public event RequestAsset OnRequestAsset; | ||
628 | public event UUIDNameRequest OnNameFromUUIDRequest; | ||
629 | public event ParcelAccessListRequest OnParcelAccessListRequest; | ||
630 | public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest; | ||
631 | public event ParcelPropertiesRequest OnParcelPropertiesRequest; | ||
632 | public event ParcelDivideRequest OnParcelDivideRequest; | ||
633 | public event ParcelJoinRequest OnParcelJoinRequest; | ||
634 | public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest; | ||
635 | public event ParcelSelectObjects OnParcelSelectObjects; | ||
636 | public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest; | ||
637 | public event ParcelAbandonRequest OnParcelAbandonRequest; | ||
638 | public event ParcelGodForceOwner OnParcelGodForceOwner; | ||
639 | public event ParcelReclaim OnParcelReclaim; | ||
640 | public event ParcelReturnObjectsRequest OnParcelReturnObjectsRequest; | ||
641 | public event ParcelDeedToGroup OnParcelDeedToGroup; | ||
642 | public event RegionInfoRequest OnRegionInfoRequest; | ||
643 | public event EstateCovenantRequest OnEstateCovenantRequest; | ||
644 | public event FriendActionDelegate OnApproveFriendRequest; | ||
645 | public event FriendActionDelegate OnDenyFriendRequest; | ||
646 | public event FriendshipTermination OnTerminateFriendship; | ||
647 | public event MoneyTransferRequest OnMoneyTransferRequest; | ||
648 | public event EconomyDataRequest OnEconomyDataRequest; | ||
649 | public event MoneyBalanceRequest OnMoneyBalanceRequest; | ||
650 | public event ParcelBuy OnParcelBuy; | ||
651 | public event UUIDNameRequest OnTeleportHomeRequest; | ||
652 | public event UUIDNameRequest OnUUIDGroupNameRequest; | ||
653 | public event ScriptAnswer OnScriptAnswer; | ||
654 | public event RequestPayPrice OnRequestPayPrice; | ||
655 | public event ObjectSaleInfo OnObjectSaleInfo; | ||
656 | public event ObjectBuy OnObjectBuy; | ||
657 | public event BuyObjectInventory OnBuyObjectInventory; | ||
658 | public event AgentSit OnUndo; | ||
659 | public event ForceReleaseControls OnForceReleaseControls; | ||
660 | public event GodLandStatRequest OnLandStatRequest; | ||
661 | public event RequestObjectPropertiesFamily OnObjectGroupRequest; | ||
662 | public event DetailedEstateDataRequest OnDetailedEstateDataRequest; | ||
663 | public event SetEstateFlagsRequest OnSetEstateFlagsRequest; | ||
664 | public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture; | ||
665 | public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture; | ||
666 | public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights; | ||
667 | public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest; | ||
668 | public event SetRegionTerrainSettings OnSetRegionTerrainSettings; | ||
669 | public event BakeTerrain OnBakeTerrain; | ||
670 | public event RequestTerrain OnUploadTerrain; | ||
671 | public event EstateChangeInfo OnEstateChangeInfo; | ||
672 | public event EstateRestartSimRequest OnEstateRestartSimRequest; | ||
673 | public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest; | ||
674 | public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest; | ||
675 | public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest; | ||
676 | public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest; | ||
677 | public event EstateDebugRegionRequest OnEstateDebugRegionRequest; | ||
678 | public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest; | ||
679 | public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; | ||
680 | public event RegionHandleRequest OnRegionHandleRequest; | ||
681 | public event ParcelInfoRequest OnParcelInfoRequest; | ||
682 | public event ScriptReset OnScriptReset; | ||
683 | public event GetScriptRunning OnGetScriptRunning; | ||
684 | public event SetScriptRunning OnSetScriptRunning; | ||
685 | public event UpdateVector OnAutoPilotGo; | ||
686 | public event TerrainUnacked OnUnackedTerrain; | ||
687 | public event ActivateGesture OnActivateGesture; | ||
688 | public event DeactivateGesture OnDeactivateGesture; | ||
689 | public event ObjectOwner OnObjectOwner; | ||
690 | public event DirPlacesQuery OnDirPlacesQuery; | ||
691 | public event DirFindQuery OnDirFindQuery; | ||
692 | public event DirLandQuery OnDirLandQuery; | ||
693 | public event DirPopularQuery OnDirPopularQuery; | ||
694 | public event DirClassifiedQuery OnDirClassifiedQuery; | ||
695 | public event EventInfoRequest OnEventInfoRequest; | ||
696 | public event ParcelSetOtherCleanTime OnParcelSetOtherCleanTime; | ||
697 | public event MapItemRequest OnMapItemRequest; | ||
698 | public event OfferCallingCard OnOfferCallingCard; | ||
699 | public event AcceptCallingCard OnAcceptCallingCard; | ||
700 | public event DeclineCallingCard OnDeclineCallingCard; | ||
701 | public event SoundTrigger OnSoundTrigger; | ||
702 | public event StartLure OnStartLure; | ||
703 | public event TeleportLureRequest OnTeleportLureRequest; | ||
704 | public event NetworkStats OnNetworkStatsUpdate; | ||
705 | public event ClassifiedInfoRequest OnClassifiedInfoRequest; | ||
706 | public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; | ||
707 | public event ClassifiedDelete OnClassifiedDelete; | ||
708 | public event ClassifiedDelete OnClassifiedGodDelete; | ||
709 | public event EventNotificationAddRequest OnEventNotificationAddRequest; | ||
710 | public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; | ||
711 | public event EventGodDelete OnEventGodDelete; | ||
712 | public event ParcelDwellRequest OnParcelDwellRequest; | ||
713 | public event UserInfoRequest OnUserInfoRequest; | ||
714 | public event UpdateUserInfo OnUpdateUserInfo; | ||
715 | public event RetrieveInstantMessages OnRetrieveInstantMessages; | ||
716 | public event PickDelete OnPickDelete; | ||
717 | public event PickGodDelete OnPickGodDelete; | ||
718 | public event PickInfoUpdate OnPickInfoUpdate; | ||
719 | public event AvatarNotesUpdate OnAvatarNotesUpdate; | ||
720 | public event MuteListRequest OnMuteListRequest; | ||
721 | public event AvatarInterestUpdate OnAvatarInterestUpdate; | ||
722 | public event PlacesQuery OnPlacesQuery; | ||
723 | |||
724 | #endregion Events | ||
725 | |||
726 | public void ActivateGesture(UUID assetId, UUID gestureId) | 612 | public void ActivateGesture(UUID assetId, UUID gestureId) |
727 | { | 613 | { |
728 | } | 614 | } |
@@ -1342,7 +1228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1342 | kill.ObjectData[0].ID = localID; | 1228 | kill.ObjectData[0].ID = localID; |
1343 | kill.Header.Reliable = true; | 1229 | kill.Header.Reliable = true; |
1344 | kill.Header.Zerocoded = true; | 1230 | kill.Header.Zerocoded = true; |
1345 | OutPacket(kill, ThrottleOutPacketType.Task); | 1231 | OutPacket(kill, ThrottleOutPacketType.State); |
1346 | } | 1232 | } |
1347 | 1233 | ||
1348 | /// <summary> | 1234 | /// <summary> |
@@ -1936,7 +1822,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1936 | sendXfer.XferID.ID = xferID; | 1822 | sendXfer.XferID.ID = xferID; |
1937 | sendXfer.XferID.Packet = packet; | 1823 | sendXfer.XferID.Packet = packet; |
1938 | sendXfer.DataPacket.Data = data; | 1824 | sendXfer.DataPacket.Data = data; |
1939 | OutPacket(sendXfer, ThrottleOutPacketType.Task); | 1825 | OutPacket(sendXfer, ThrottleOutPacketType.Asset); |
1940 | } | 1826 | } |
1941 | 1827 | ||
1942 | public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, | 1828 | public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, |
@@ -2218,7 +2104,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2218 | packet.AgentData.SessionID = SessionId; | 2104 | packet.AgentData.SessionID = SessionId; |
2219 | packet.Header.Reliable = false; | 2105 | packet.Header.Reliable = false; |
2220 | packet.Header.Zerocoded = true; | 2106 | packet.Header.Zerocoded = true; |
2221 | OutPacket(packet, ThrottleOutPacketType.Task); | 2107 | OutPacket(packet, ThrottleOutPacketType.State); |
2222 | } | 2108 | } |
2223 | 2109 | ||
2224 | public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, | 2110 | public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, |
@@ -3241,7 +3127,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3241 | 3127 | ||
3242 | avp.Sender.IsTrial = false; | 3128 | avp.Sender.IsTrial = false; |
3243 | avp.Sender.ID = agentID; | 3129 | avp.Sender.ID = agentID; |
3244 | OutPacket(avp, ThrottleOutPacketType.Task); | 3130 | OutPacket(avp, ThrottleOutPacketType.State); |
3245 | } | 3131 | } |
3246 | 3132 | ||
3247 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) | 3133 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) |
@@ -3366,7 +3252,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3366 | int length = 0; | 3252 | int length = 0; |
3367 | m_avatarTerseUpdates[count].ToBytes(blockbuffer, ref length); | 3253 | m_avatarTerseUpdates[count].ToBytes(blockbuffer, ref length); |
3368 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | 3254 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); |
3369 | if (size + length > m_packetMTU) | 3255 | if (size + length > Packet.MTU) |
3370 | break; | 3256 | break; |
3371 | size += length; | 3257 | size += length; |
3372 | } | 3258 | } |
@@ -3381,6 +3267,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3381 | 3267 | ||
3382 | terse.Header.Reliable = false; | 3268 | terse.Header.Reliable = false; |
3383 | terse.Header.Zerocoded = true; | 3269 | terse.Header.Zerocoded = true; |
3270 | // FIXME: Move this to ThrottleOutPacketType.State when the real prioritization code is committed | ||
3384 | OutPacket(terse, ThrottleOutPacketType.Task); | 3271 | OutPacket(terse, ThrottleOutPacketType.Task); |
3385 | 3272 | ||
3386 | if (m_avatarTerseUpdates.Count == 0) | 3273 | if (m_avatarTerseUpdates.Count == 0) |
@@ -3571,7 +3458,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3571 | void ProcessTextureRequests() | 3458 | void ProcessTextureRequests() |
3572 | { | 3459 | { |
3573 | if (m_imageManager != null) | 3460 | if (m_imageManager != null) |
3574 | m_imageManager.ProcessImageQueue(m_textureSendLimit, m_textureDataLimit); | 3461 | m_imageManager.ProcessImageQueue(m_textureSendLimit); |
3575 | } | 3462 | } |
3576 | 3463 | ||
3577 | void ProcessPrimFullUpdates(object sender, ElapsedEventArgs e) | 3464 | void ProcessPrimFullUpdates(object sender, ElapsedEventArgs e) |
@@ -3610,7 +3497,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3610 | int length = 0; | 3497 | int length = 0; |
3611 | m_primFullUpdates[count].ToBytes(blockbuffer, ref length); | 3498 | m_primFullUpdates[count].ToBytes(blockbuffer, ref length); |
3612 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | 3499 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); |
3613 | if (size + length > m_packetMTU) | 3500 | if (size + length > Packet.MTU) |
3614 | break; | 3501 | break; |
3615 | size += length; | 3502 | size += length; |
3616 | } | 3503 | } |
@@ -3625,7 +3512,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3625 | } | 3512 | } |
3626 | 3513 | ||
3627 | outPacket.Header.Zerocoded = true; | 3514 | outPacket.Header.Zerocoded = true; |
3628 | OutPacket(outPacket, ThrottleOutPacketType.Task); | 3515 | OutPacket(outPacket, ThrottleOutPacketType.State); |
3629 | 3516 | ||
3630 | if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) | 3517 | if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) |
3631 | lock (m_primFullUpdateTimer) | 3518 | lock (m_primFullUpdateTimer) |
@@ -3698,7 +3585,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3698 | int length = 0; | 3585 | int length = 0; |
3699 | m_primTerseUpdates[count].ToBytes(blockbuffer, ref length); | 3586 | m_primTerseUpdates[count].ToBytes(blockbuffer, ref length); |
3700 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | 3587 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); |
3701 | if (size + length > m_packetMTU) | 3588 | if (size + length > Packet.MTU) |
3702 | break; | 3589 | break; |
3703 | size += length; | 3590 | size += length; |
3704 | } | 3591 | } |
@@ -3715,7 +3602,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3715 | 3602 | ||
3716 | outPacket.Header.Reliable = false; | 3603 | outPacket.Header.Reliable = false; |
3717 | outPacket.Header.Zerocoded = true; | 3604 | outPacket.Header.Zerocoded = true; |
3718 | OutPacket(outPacket, ThrottleOutPacketType.Task); | 3605 | OutPacket(outPacket, ThrottleOutPacketType.State); |
3719 | 3606 | ||
3720 | if (m_primTerseUpdates.Count == 0) | 3607 | if (m_primTerseUpdates.Count == 0) |
3721 | lock (m_primTerseUpdateTimer) | 3608 | lock (m_primTerseUpdateTimer) |
@@ -4801,7 +4688,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4801 | 4688 | ||
4802 | public bool HandleObjectGroupRequest(IClientAPI sender, Packet Pack) | 4689 | public bool HandleObjectGroupRequest(IClientAPI sender, Packet Pack) |
4803 | { | 4690 | { |
4804 | |||
4805 | ObjectGroupPacket ogpack = (ObjectGroupPacket)Pack; | 4691 | ObjectGroupPacket ogpack = (ObjectGroupPacket)Pack; |
4806 | if (ogpack.AgentData.SessionID != SessionId) return false; | 4692 | if (ogpack.AgentData.SessionID != SessionId) return false; |
4807 | 4693 | ||
@@ -7013,7 +6899,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7013 | #endregion | 6899 | #endregion |
7014 | 6900 | ||
7015 | //handlerTextureRequest = null; | 6901 | //handlerTextureRequest = null; |
7016 | |||
7017 | for (int i = 0; i < imageRequest.RequestImage.Length; i++) | 6902 | for (int i = 0; i < imageRequest.RequestImage.Length; i++) |
7018 | { | 6903 | { |
7019 | if (OnRequestTexture != null) | 6904 | if (OnRequestTexture != null) |
@@ -7024,7 +6909,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7024 | args.PacketNumber = imageRequest.RequestImage[i].Packet; | 6909 | args.PacketNumber = imageRequest.RequestImage[i].Packet; |
7025 | args.Priority = imageRequest.RequestImage[i].DownloadPriority; | 6910 | args.Priority = imageRequest.RequestImage[i].DownloadPriority; |
7026 | args.requestSequence = imageRequest.Header.Sequence; | 6911 | args.requestSequence = imageRequest.Header.Sequence; |
7027 | |||
7028 | //handlerTextureRequest = OnRequestTexture; | 6912 | //handlerTextureRequest = OnRequestTexture; |
7029 | 6913 | ||
7030 | //if (handlerTextureRequest != null) | 6914 | //if (handlerTextureRequest != null) |
@@ -7047,10 +6931,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7047 | // Validate inventory transfers | 6931 | // Validate inventory transfers |
7048 | // Has to be done here, because AssetCache can't do it | 6932 | // Has to be done here, because AssetCache can't do it |
7049 | // | 6933 | // |
7050 | 6934 | UUID taskID = UUID.Zero; | |
7051 | if (transfer.TransferInfo.SourceType == 3) | 6935 | if (transfer.TransferInfo.SourceType == 3) |
7052 | { | 6936 | { |
7053 | UUID taskID = new UUID(transfer.TransferInfo.Params, 48); | 6937 | taskID = new UUID(transfer.TransferInfo.Params, 48); |
7054 | UUID itemID = new UUID(transfer.TransferInfo.Params, 64); | 6938 | UUID itemID = new UUID(transfer.TransferInfo.Params, 64); |
7055 | UUID requestID = new UUID(transfer.TransferInfo.Params, 80); | 6939 | UUID requestID = new UUID(transfer.TransferInfo.Params, 80); |
7056 | if (!(((Scene)m_scene).Permissions.BypassPermissions())) | 6940 | if (!(((Scene)m_scene).Permissions.BypassPermissions())) |
@@ -7121,7 +7005,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7121 | 7005 | ||
7122 | //m_assetCache.AddAssetRequest(this, transfer); | 7006 | //m_assetCache.AddAssetRequest(this, transfer); |
7123 | 7007 | ||
7124 | MakeAssetRequest(transfer); | 7008 | MakeAssetRequest(transfer, taskID); |
7125 | 7009 | ||
7126 | /* RequestAsset = OnRequestAsset; | 7010 | /* RequestAsset = OnRequestAsset; |
7127 | if (RequestAsset != null) | 7011 | if (RequestAsset != null) |
@@ -10250,7 +10134,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10250 | 10134 | ||
10251 | public void KillEndDone() | 10135 | public void KillEndDone() |
10252 | { | 10136 | { |
10253 | m_udpClient.Shutdown(); | ||
10254 | } | 10137 | } |
10255 | 10138 | ||
10256 | #region IClientCore | 10139 | #region IClientCore |
@@ -10293,15 +10176,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10293 | { | 10176 | { |
10294 | Kick(reason); | 10177 | Kick(reason); |
10295 | Thread.Sleep(1000); | 10178 | Thread.Sleep(1000); |
10296 | Close(true); | 10179 | Close(); |
10297 | } | 10180 | } |
10298 | 10181 | ||
10299 | public void Disconnect() | 10182 | public void Disconnect() |
10300 | { | 10183 | { |
10301 | Close(true); | 10184 | Close(); |
10302 | } | 10185 | } |
10303 | 10186 | ||
10304 | |||
10305 | #endregion | 10187 | #endregion |
10306 | 10188 | ||
10307 | public void RefreshGroupMembership() | 10189 | public void RefreshGroupMembership() |
@@ -10330,7 +10212,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10330 | return String.Empty; | 10212 | return String.Empty; |
10331 | } | 10213 | } |
10332 | 10214 | ||
10333 | public void MakeAssetRequest(TransferRequestPacket transferRequest) | 10215 | public void MakeAssetRequest(TransferRequestPacket transferRequest, UUID taskID) |
10334 | { | 10216 | { |
10335 | UUID requestID = UUID.Zero; | 10217 | UUID requestID = UUID.Zero; |
10336 | if (transferRequest.TransferInfo.SourceType == 2) | 10218 | if (transferRequest.TransferInfo.SourceType == 2) |
@@ -10342,12 +10224,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10342 | { | 10224 | { |
10343 | //inventory asset request | 10225 | //inventory asset request |
10344 | requestID = new UUID(transferRequest.TransferInfo.Params, 80); | 10226 | requestID = new UUID(transferRequest.TransferInfo.Params, 80); |
10345 | //m_log.Debug("asset request " + requestID); | 10227 | //m_log.Debug("[XXX] inventory asset request " + requestID); |
10228 | //if (taskID == UUID.Zero) // Agent | ||
10229 | // if (m_scene is HGScene) | ||
10230 | // { | ||
10231 | // m_log.Debug("[XXX] hg asset request " + requestID); | ||
10232 | // // We may need to fetch the asset from the user's asset server into the local asset server | ||
10233 | // HGAssetMapper mapper = ((HGScene)m_scene).AssetMapper; | ||
10234 | // mapper.Get(requestID, AgentId); | ||
10235 | // } | ||
10346 | } | 10236 | } |
10347 | 10237 | ||
10348 | //check to see if asset is in local cache, if not we need to request it from asset server. | 10238 | //check to see if asset is in local cache, if not we need to request it from asset server. |
10349 | //m_log.Debug("asset request " + requestID); | 10239 | //m_log.Debug("asset request " + requestID); |
10350 | 10240 | ||
10351 | m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); | 10241 | m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); |
10352 | 10242 | ||
10353 | } | 10243 | } |
@@ -10358,12 +10248,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10358 | 10248 | ||
10359 | UUID requestID = UUID.Zero; | 10249 | UUID requestID = UUID.Zero; |
10360 | byte source = 2; | 10250 | byte source = 2; |
10361 | if (transferRequest.TransferInfo.SourceType == 2) | 10251 | if ((transferRequest.TransferInfo.SourceType == 2) || (transferRequest.TransferInfo.SourceType == 2222)) |
10362 | { | 10252 | { |
10363 | //direct asset request | 10253 | //direct asset request |
10364 | requestID = new UUID(transferRequest.TransferInfo.Params, 0); | 10254 | requestID = new UUID(transferRequest.TransferInfo.Params, 0); |
10365 | } | 10255 | } |
10366 | else if (transferRequest.TransferInfo.SourceType == 3) | 10256 | else if ((transferRequest.TransferInfo.SourceType == 3) || (transferRequest.TransferInfo.SourceType == 3333)) |
10367 | { | 10257 | { |
10368 | //inventory asset request | 10258 | //inventory asset request |
10369 | requestID = new UUID(transferRequest.TransferInfo.Params, 80); | 10259 | requestID = new UUID(transferRequest.TransferInfo.Params, 80); |
@@ -10371,10 +10261,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10371 | //m_log.Debug("asset request " + requestID); | 10261 | //m_log.Debug("asset request " + requestID); |
10372 | } | 10262 | } |
10373 | 10263 | ||
10374 | // FIXME: We never tell the client about assets which do not exist when requested by this transfer mechanism, which can't be right. | ||
10375 | if (null == asset) | 10264 | if (null == asset) |
10376 | { | 10265 | { |
10266 | if ((m_hyperAssets != null) && (transferRequest.TransferInfo.SourceType < 2000)) | ||
10267 | { | ||
10268 | // Try the user's inventory, but only if it's different from the regions' | ||
10269 | string userAssets = m_hyperAssets.GetUserAssetServer(AgentId); | ||
10270 | if ((userAssets != string.Empty) && (userAssets != m_hyperAssets.GetSimAssetServer())) | ||
10271 | { | ||
10272 | m_log.DebugFormat("[CLIENT]: asset {0} not found in local asset storage. Trying user's storage.", id); | ||
10273 | if (transferRequest.TransferInfo.SourceType == 2) | ||
10274 | transferRequest.TransferInfo.SourceType = 2222; // marker | ||
10275 | else if (transferRequest.TransferInfo.SourceType == 3) | ||
10276 | transferRequest.TransferInfo.SourceType = 3333; // marker | ||
10277 | |||
10278 | m_assetService.Get(userAssets + "/" + id, transferRequest, AssetReceived); | ||
10279 | return; | ||
10280 | } | ||
10281 | } | ||
10282 | |||
10377 | //m_log.DebugFormat("[ASSET CACHE]: Asset transfer request for asset which is {0} already known to be missing. Dropping", requestID); | 10283 | //m_log.DebugFormat("[ASSET CACHE]: Asset transfer request for asset which is {0} already known to be missing. Dropping", requestID); |
10284 | |||
10285 | // FIXME: We never tell the client about assets which do not exist when requested by this transfer mechanism, which can't be right. | ||
10378 | return; | 10286 | return; |
10379 | } | 10287 | } |
10380 | 10288 | ||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs index 343f537..d25bf95 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs | |||
@@ -59,6 +59,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
59 | private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer()); | 59 | private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer()); |
60 | private object m_syncRoot = new object(); | 60 | private object m_syncRoot = new object(); |
61 | 61 | ||
62 | private IHyperAssetService m_hyperAssets; | ||
63 | |||
62 | public LLClientView Client { get { return m_client; } } | 64 | public LLClientView Client { get { return m_client; } } |
63 | public AssetBase MissingImage { get { return m_missingImage; } } | 65 | public AssetBase MissingImage { get { return m_missingImage; } } |
64 | 66 | ||
@@ -74,6 +76,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
74 | m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client"); | 76 | m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client"); |
75 | 77 | ||
76 | m_j2kDecodeModule = pJ2kDecodeModule; | 78 | m_j2kDecodeModule = pJ2kDecodeModule; |
79 | m_hyperAssets = client.Scene.RequestModuleInterface<IHyperAssetService>(); | ||
77 | } | 80 | } |
78 | 81 | ||
79 | /// <summary> | 82 | /// <summary> |
@@ -146,6 +149,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
146 | imgrequest = new J2KImage(this); | 149 | imgrequest = new J2KImage(this); |
147 | imgrequest.J2KDecoder = m_j2kDecodeModule; | 150 | imgrequest.J2KDecoder = m_j2kDecodeModule; |
148 | imgrequest.AssetService = m_assetCache; | 151 | imgrequest.AssetService = m_assetCache; |
152 | imgrequest.AgentID = m_client.AgentId; | ||
153 | imgrequest.HyperAssets = m_hyperAssets; | ||
149 | imgrequest.DiscardLevel = newRequest.DiscardLevel; | 154 | imgrequest.DiscardLevel = newRequest.DiscardLevel; |
150 | imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber); | 155 | imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber); |
151 | imgrequest.Priority = newRequest.Priority; | 156 | imgrequest.Priority = newRequest.Priority; |
@@ -162,47 +167,48 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
162 | } | 167 | } |
163 | } | 168 | } |
164 | 169 | ||
165 | public bool ProcessImageQueue(int count, int maxpack) | 170 | public bool ProcessImageQueue(int packetsToSend) |
166 | { | 171 | { |
167 | J2KImage imagereq; | 172 | m_lastloopprocessed = DateTime.Now.Ticks; |
168 | int numCollected = 0; | 173 | int packetsSent = 0; |
169 | 174 | ||
170 | //lock (m_syncRoot) | 175 | while (packetsSent < packetsToSend) |
171 | //{ | 176 | { |
172 | m_lastloopprocessed = DateTime.Now.Ticks; | 177 | J2KImage image = GetHighestPriorityImage(); |
173 | 178 | ||
174 | // This can happen during Close() | 179 | // If null was returned, the texture priority queue is currently empty |
175 | if (m_client == null) | 180 | if (image == null) |
176 | return false; | 181 | return false; |
177 | |||
178 | while ((imagereq = GetHighestPriorityImage()) != null) | ||
179 | { | ||
180 | if (imagereq.IsDecoded == true) | ||
181 | { | ||
182 | ++numCollected; | ||
183 | 182 | ||
184 | if (imagereq.SendPackets(m_client, maxpack)) | 183 | if (image.IsDecoded) |
185 | { | 184 | { |
186 | // Send complete. Destroy any knowledge of this transfer | 185 | int sent; |
187 | RemoveImageFromQueue(imagereq); | 186 | bool imageDone = image.SendPackets(m_client, packetsToSend - packetsSent, out sent); |
188 | } | 187 | packetsSent += sent; |
189 | } | ||
190 | 188 | ||
191 | if (numCollected == count) | 189 | // If the send is complete, destroy any knowledge of this transfer |
192 | break; | 190 | if (imageDone) |
191 | RemoveImageFromQueue(image); | ||
192 | } | ||
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; | ||
193 | } | 200 | } |
194 | //} | 201 | } |
195 | 202 | ||
196 | return m_priorityQueue.Count > 0; | 203 | return m_priorityQueue.Count > 0; |
197 | } | 204 | } |
198 | 205 | ||
199 | //Faux destructor | 206 | /// <summary> |
207 | /// Faux destructor | ||
208 | /// </summary> | ||
200 | public void Close() | 209 | public void Close() |
201 | { | 210 | { |
202 | m_shuttingdown = true; | 211 | m_shuttingdown = true; |
203 | m_j2kDecodeModule = null; | ||
204 | m_assetCache = null; | ||
205 | m_client = null; | ||
206 | } | 212 | } |
207 | 213 | ||
208 | #region Priority Queue Helpers | 214 | #region Priority Queue Helpers |
@@ -213,13 +219,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
213 | 219 | ||
214 | lock (m_syncRoot) | 220 | lock (m_syncRoot) |
215 | { | 221 | { |
216 | |||
217 | if (m_priorityQueue.Count > 0) | 222 | if (m_priorityQueue.Count > 0) |
218 | { | 223 | { |
219 | try | 224 | try { image = m_priorityQueue.FindMax(); } |
220 | { | ||
221 | image = m_priorityQueue.FindMax(); | ||
222 | } | ||
223 | catch (Exception) { } | 225 | catch (Exception) { } |
224 | } | 226 | } |
225 | } | 227 | } |
@@ -231,20 +233,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
231 | image.PriorityQueueHandle = null; | 233 | image.PriorityQueueHandle = null; |
232 | 234 | ||
233 | lock (m_syncRoot) | 235 | lock (m_syncRoot) |
234 | try | 236 | try { m_priorityQueue.Add(ref image.PriorityQueueHandle, image); } |
235 | { | ||
236 | m_priorityQueue.Add(ref image.PriorityQueueHandle, image); | ||
237 | } | ||
238 | catch (Exception) { } | 237 | catch (Exception) { } |
239 | } | 238 | } |
240 | 239 | ||
241 | void RemoveImageFromQueue(J2KImage image) | 240 | void RemoveImageFromQueue(J2KImage image) |
242 | { | 241 | { |
243 | lock (m_syncRoot) | 242 | lock (m_syncRoot) |
244 | try | 243 | try { m_priorityQueue.Delete(image.PriorityQueueHandle); } |
245 | { | ||
246 | m_priorityQueue.Delete(image.PriorityQueueHandle); | ||
247 | } | ||
248 | catch (Exception) { } | 244 | catch (Exception) { } |
249 | } | 245 | } |
250 | 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..545a0bc 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,19 @@ 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; | ||
116 | /// <summary>Flag to process packets asynchronously or synchronously</summary> | ||
117 | private bool m_asyncPacketHandling; | ||
112 | 118 | ||
113 | /// <summary>The measured resolution of Environment.TickCount</summary> | 119 | /// <summary>The measured resolution of Environment.TickCount</summary> |
114 | public float TickCountResolution { get { return m_tickCountResolution; } } | 120 | public float TickCountResolution { get { return m_tickCountResolution; } } |
115 | public Socket Server { get { return null; } } | 121 | public Socket Server { get { return null; } } |
116 | 122 | ||
117 | public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) | 123 | public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) |
118 | : base((int)port) | 124 | : base(listenIP, (int)port) |
119 | { | 125 | { |
120 | #region Environment.TickCount Measurement | 126 | #region Environment.TickCount Measurement |
121 | 127 | ||
@@ -134,18 +140,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
134 | #endregion Environment.TickCount Measurement | 140 | #endregion Environment.TickCount Measurement |
135 | 141 | ||
136 | m_circuitManager = circuitManager; | 142 | m_circuitManager = circuitManager; |
143 | int sceneThrottleBps = 0; | ||
137 | 144 | ||
138 | // TODO: Config support for throttling the entire connection | 145 | IConfig config = configSource.Configs["ClientStack.LindenUDP"]; |
139 | m_throttle = new TokenBucket(null, 0, 0); | 146 | if (config != null) |
147 | { | ||
148 | m_asyncPacketHandling = config.GetBoolean("async_packet_handling", false); | ||
149 | m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0); | ||
150 | sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0); | ||
151 | } | ||
152 | |||
153 | m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps); | ||
140 | m_throttleRates = new ThrottleRates(configSource); | 154 | m_throttleRates = new ThrottleRates(configSource); |
141 | } | 155 | } |
142 | 156 | ||
143 | public new void Start() | 157 | public void Start() |
144 | { | 158 | { |
145 | if (m_scene == null) | 159 | if (m_scene == null) |
146 | throw new InvalidOperationException("Cannot LLUDPServer.Start() without an IScene reference"); | 160 | throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); |
161 | |||
162 | m_log.Info("[LLUDPSERVER]: Starting the LLUDP server in " + (m_asyncPacketHandling ? "asynchronous" : "synchronous") + " mode"); | ||
147 | 163 | ||
148 | base.Start(); | 164 | base.Start(m_recvBufferSize, m_asyncPacketHandling); |
149 | 165 | ||
150 | // Start the incoming packet processing thread | 166 | // Start the incoming packet processing thread |
151 | Thread incomingThread = new Thread(IncomingPacketHandler); | 167 | Thread incomingThread = new Thread(IncomingPacketHandler); |
@@ -181,24 +197,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
181 | return x == m_location; | 197 | return x == m_location; |
182 | } | 198 | } |
183 | 199 | ||
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) | 200 | public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) |
203 | { | 201 | { |
204 | // CoarseLocationUpdate packets cannot be split in an automated way | 202 | // CoarseLocationUpdate packets cannot be split in an automated way |
@@ -216,30 +214,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
216 | for (int i = 0; i < packetCount; i++) | 214 | for (int i = 0; i < packetCount; i++) |
217 | { | 215 | { |
218 | byte[] data = datas[i]; | 216 | byte[] data = datas[i]; |
219 | clients.ForEach( | 217 | m_scene.ClientManager.ForEach( |
220 | delegate(LLUDPClient client) | 218 | delegate(IClientAPI client) |
221 | { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); | 219 | { |
220 | if (client is LLClientView) | ||
221 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category); | ||
222 | } | ||
223 | ); | ||
222 | } | 224 | } |
223 | } | 225 | } |
224 | else | 226 | else |
225 | { | 227 | { |
226 | byte[] data = packet.ToBytes(); | 228 | byte[] data = packet.ToBytes(); |
227 | clients.ForEach( | 229 | m_scene.ClientManager.ForEach( |
228 | delegate(LLUDPClient client) | 230 | delegate(IClientAPI client) |
229 | { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); | 231 | { |
232 | if (client is LLClientView) | ||
233 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category); | ||
234 | } | ||
235 | ); | ||
230 | } | 236 | } |
231 | } | 237 | } |
232 | 238 | ||
233 | public void SendPacket(UUID agentID, Packet packet, ThrottleOutPacketType category, bool allowSplitting) | 239 | 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 | { | 240 | { |
244 | // CoarseLocationUpdate packets cannot be split in an automated way | 241 | // CoarseLocationUpdate packets cannot be split in an automated way |
245 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) | 242 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) |
@@ -256,25 +253,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
256 | for (int i = 0; i < packetCount; i++) | 253 | for (int i = 0; i < packetCount; i++) |
257 | { | 254 | { |
258 | byte[] data = datas[i]; | 255 | byte[] data = datas[i]; |
259 | SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); | 256 | SendPacketData(udpClient, data, packet.Type, category); |
260 | } | 257 | } |
261 | } | 258 | } |
262 | else | 259 | else |
263 | { | 260 | { |
264 | byte[] data = packet.ToBytes(); | 261 | byte[] data = packet.ToBytes(); |
265 | SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); | 262 | SendPacketData(udpClient, data, packet.Type, category); |
266 | } | 263 | } |
267 | } | 264 | } |
268 | 265 | ||
269 | public void SendPacketData(LLUDPClient client, byte[] data, int dataLength, PacketType type, bool doZerocode, ThrottleOutPacketType category) | 266 | public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category) |
270 | { | 267 | { |
268 | int dataLength = data.Length; | ||
269 | bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; | ||
270 | |||
271 | // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. | 271 | // 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 | 272 | // 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 | 273 | // 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 | 274 | // to accomodate for both common scenarios and provide ample room for ACK appending in both |
275 | int bufferSize = (dataLength > 180) ? Packet.MTU : 200; | 275 | int bufferSize = (dataLength > 180) ? Packet.MTU : 200; |
276 | 276 | ||
277 | UDPPacketBuffer buffer = new UDPPacketBuffer(client.RemoteEndPoint, bufferSize); | 277 | UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); |
278 | 278 | ||
279 | // Zerocode if needed | 279 | // Zerocode if needed |
280 | if (doZerocode) | 280 | if (doZerocode) |
@@ -285,17 +285,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
285 | // The packet grew larger than the bufferSize while zerocoding. | 285 | // The packet grew larger than the bufferSize while zerocoding. |
286 | // Remove the MSG_ZEROCODED flag and send the unencoded data | 286 | // Remove the MSG_ZEROCODED flag and send the unencoded data |
287 | // instead | 287 | // instead |
288 | m_log.Info("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding. Removing MSG_ZEROCODED flag"); | 288 | 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); | 289 | 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); | 290 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); |
294 | } | 291 | } |
295 | } | 292 | } |
296 | else | 293 | else |
297 | { | 294 | { |
298 | // ??? will it fit? | ||
299 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | 295 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); |
300 | } | 296 | } |
301 | buffer.DataLength = dataLength; | 297 | buffer.DataLength = dataLength; |
@@ -303,7 +299,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
303 | #region Queue or Send | 299 | #region Queue or Send |
304 | 300 | ||
305 | // Look up the UDPClient this is going to | 301 | // Look up the UDPClient this is going to |
306 | OutgoingPacket outgoingPacket = new OutgoingPacket(client, buffer, category); | 302 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); |
307 | 303 | ||
308 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) | 304 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) |
309 | SendPacketFinal(outgoingPacket); | 305 | SendPacketFinal(outgoingPacket); |
@@ -311,18 +307,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
311 | #endregion Queue or Send | 307 | #endregion Queue or Send |
312 | } | 308 | } |
313 | 309 | ||
314 | public void SendAcks(LLUDPClient client) | 310 | public void SendAcks(LLUDPClient udpClient) |
315 | { | 311 | { |
316 | uint ack; | 312 | uint ack; |
317 | 313 | ||
318 | if (client.PendingAcks.Dequeue(out ack)) | 314 | if (udpClient.PendingAcks.Dequeue(out ack)) |
319 | { | 315 | { |
320 | List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>(); | 316 | List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>(); |
321 | PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); | 317 | PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); |
322 | block.ID = ack; | 318 | block.ID = ack; |
323 | blocks.Add(block); | 319 | blocks.Add(block); |
324 | 320 | ||
325 | while (client.PendingAcks.Dequeue(out ack)) | 321 | while (udpClient.PendingAcks.Dequeue(out ack)) |
326 | { | 322 | { |
327 | block = new PacketAckPacket.PacketsBlock(); | 323 | block = new PacketAckPacket.PacketsBlock(); |
328 | block.ID = ack; | 324 | block.ID = ack; |
@@ -333,22 +329,39 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
333 | packet.Header.Reliable = false; | 329 | packet.Header.Reliable = false; |
334 | packet.Packets = blocks.ToArray(); | 330 | packet.Packets = blocks.ToArray(); |
335 | 331 | ||
336 | SendPacket(client, packet, ThrottleOutPacketType.Unknown, true); | 332 | SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true); |
337 | } | 333 | } |
338 | } | 334 | } |
339 | 335 | ||
340 | public void SendPing(LLUDPClient client) | 336 | public void SendPing(LLUDPClient udpClient) |
341 | { | 337 | { |
342 | IClientAPI api = client.ClientAPI; | 338 | StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); |
343 | if (api != null) | 339 | pc.Header.Reliable = false; |
344 | api.SendStartPingCheck(client.CurrentPingSequence++); | 340 | |
341 | OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest(); | ||
342 | |||
343 | pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++; | ||
344 | pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0; | ||
345 | |||
346 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); | ||
345 | } | 347 | } |
346 | 348 | ||
347 | public void ResendUnacked(LLUDPClient client) | 349 | public void ResendUnacked(LLUDPClient udpClient) |
348 | { | 350 | { |
349 | if (client.NeedAcks.Count > 0) | 351 | if (udpClient.IsConnected && udpClient.NeedAcks.Count > 0) |
350 | { | 352 | { |
351 | List<OutgoingPacket> expiredPackets = client.NeedAcks.GetExpiredPackets(client.RTO); | 353 | // Disconnect an agent if no packets are received for some time |
354 | //FIXME: Make 60 an .ini setting | ||
355 | if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60) | ||
356 | { | ||
357 | m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); | ||
358 | |||
359 | RemoveClient(udpClient); | ||
360 | return; | ||
361 | } | ||
362 | |||
363 | // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO | ||
364 | List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); | ||
352 | 365 | ||
353 | if (expiredPackets != null) | 366 | if (expiredPackets != null) |
354 | { | 367 | { |
@@ -357,54 +370,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
357 | { | 370 | { |
358 | OutgoingPacket outgoingPacket = expiredPackets[i]; | 371 | OutgoingPacket outgoingPacket = expiredPackets[i]; |
359 | 372 | ||
360 | // FIXME: Make this an .ini setting | 373 | //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed", |
361 | if (outgoingPacket.ResendCount < 3) | 374 | // 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 | 375 | ||
370 | // The TickCount will be set to the current time when the packet | 376 | // Set the resent flag |
371 | // is actually sent out again | 377 | outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); |
372 | outgoingPacket.TickCount = 0; | 378 | outgoingPacket.Category = ThrottleOutPacketType.Resend; |
373 | 379 | ||
374 | // Bump up the resend count on this packet | 380 | // The TickCount will be set to the current time when the packet |
375 | Interlocked.Increment(ref outgoingPacket.ResendCount); | 381 | // is actually sent out again |
376 | //Interlocked.Increment(ref Stats.ResentPackets); | 382 | outgoingPacket.TickCount = 0; |
377 | 383 | ||
378 | // Queue or (re)send the packet | 384 | // Bump up the resend count on this packet |
379 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) | 385 | Interlocked.Increment(ref outgoingPacket.ResendCount); |
380 | SendPacketFinal(outgoingPacket); | 386 | //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 | 387 | ||
387 | lock (client.NeedAcks.SyncRoot) | 388 | // Requeue or resend the packet |
388 | client.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber); | 389 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) |
389 | 390 | 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 | } | 391 | } |
403 | } | 392 | } |
404 | } | 393 | } |
405 | } | 394 | } |
406 | 395 | ||
407 | public void Flush() | 396 | public void Flush(LLUDPClient udpClient) |
408 | { | 397 | { |
409 | // FIXME: Implement? | 398 | // FIXME: Implement? |
410 | } | 399 | } |
@@ -415,7 +404,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
415 | byte flags = buffer.Data[0]; | 404 | byte flags = buffer.Data[0]; |
416 | bool isResend = (flags & Helpers.MSG_RESENT) != 0; | 405 | bool isResend = (flags & Helpers.MSG_RESENT) != 0; |
417 | bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; | 406 | bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; |
418 | LLUDPClient client = outgoingPacket.Client; | 407 | LLUDPClient udpClient = outgoingPacket.Client; |
408 | |||
409 | if (!udpClient.IsConnected) | ||
410 | return; | ||
419 | 411 | ||
420 | // Keep track of when this packet was sent out (right now) | 412 | // Keep track of when this packet was sent out (right now) |
421 | outgoingPacket.TickCount = Environment.TickCount; | 413 | outgoingPacket.TickCount = Environment.TickCount; |
@@ -424,11 +416,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
424 | 416 | ||
425 | int dataLength = buffer.DataLength; | 417 | int dataLength = buffer.DataLength; |
426 | 418 | ||
427 | // Keep appending ACKs until there is no room left in the packet or there are | 419 | // Keep appending ACKs until there is no room left in the buffer or there are |
428 | // no more ACKs to append | 420 | // no more ACKs to append |
429 | uint ackCount = 0; | 421 | uint ackCount = 0; |
430 | uint ack; | 422 | uint ack; |
431 | while (dataLength + 5 < buffer.Data.Length && client.PendingAcks.Dequeue(out ack)) | 423 | while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack)) |
432 | { | 424 | { |
433 | Utils.UIntToBytesBig(ack, buffer.Data, dataLength); | 425 | Utils.UIntToBytesBig(ack, buffer.Data, dataLength); |
434 | dataLength += 4; | 426 | dataLength += 4; |
@@ -447,24 +439,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
447 | 439 | ||
448 | #endregion ACK Appending | 440 | #endregion ACK Appending |
449 | 441 | ||
442 | #region Sequence Number Assignment | ||
443 | |||
450 | if (!isResend) | 444 | if (!isResend) |
451 | { | 445 | { |
452 | // Not a resend, assign a new sequence number | 446 | // Not a resend, assign a new sequence number |
453 | uint sequenceNumber = (uint)Interlocked.Increment(ref client.CurrentSequence); | 447 | uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence); |
454 | Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); | 448 | Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); |
455 | outgoingPacket.SequenceNumber = sequenceNumber; | 449 | outgoingPacket.SequenceNumber = sequenceNumber; |
456 | 450 | ||
457 | if (isReliable) | 451 | if (isReliable) |
458 | { | 452 | { |
459 | // Add this packet to the list of ACK responses we are waiting on from the server | 453 | // Add this packet to the list of ACK responses we are waiting on from the server |
460 | client.NeedAcks.Add(outgoingPacket); | 454 | udpClient.NeedAcks.Add(outgoingPacket); |
461 | } | 455 | } |
462 | } | 456 | } |
463 | 457 | ||
458 | #endregion Sequence Number Assignment | ||
459 | |||
464 | // Stats tracking | 460 | // Stats tracking |
465 | Interlocked.Increment(ref client.PacketsSent); | 461 | Interlocked.Increment(ref udpClient.PacketsSent); |
466 | if (isReliable) | 462 | if (isReliable) |
467 | Interlocked.Add(ref client.UnackedBytes, outgoingPacket.Buffer.DataLength); | 463 | Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength); |
468 | 464 | ||
469 | // Put the UDP payload on the wire | 465 | // Put the UDP payload on the wire |
470 | AsyncBeginSend(buffer); | 466 | AsyncBeginSend(buffer); |
@@ -473,10 +469,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
473 | protected override void PacketReceived(UDPPacketBuffer buffer) | 469 | protected override void PacketReceived(UDPPacketBuffer buffer) |
474 | { | 470 | { |
475 | // Debugging/Profiling | 471 | // Debugging/Profiling |
476 | //try { Thread.CurrentThread.Name = "PacketReceived (" + scene.RegionName + ")"; } | 472 | //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; } |
477 | //catch (Exception) { } | 473 | //catch (Exception) { } |
478 | 474 | ||
479 | LLUDPClient client = null; | 475 | LLUDPClient udpClient = null; |
480 | Packet packet = null; | 476 | Packet packet = null; |
481 | int packetEnd = buffer.DataLength - 1; | 477 | int packetEnd = buffer.DataLength - 1; |
482 | IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; | 478 | IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; |
@@ -491,61 +487,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
491 | } | 487 | } |
492 | catch (MalformedDataException) | 488 | catch (MalformedDataException) |
493 | { | 489 | { |
494 | m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet:\n{0}", | 490 | m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet from {0}:\n{1}", |
495 | Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | 491 | buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); |
496 | } | 492 | } |
497 | 493 | ||
498 | // Fail-safe check | 494 | // Fail-safe check |
499 | if (packet == null) | 495 | if (packet == null) |
500 | { | 496 | { |
501 | m_log.Warn("[LLUDPSERVER]: Couldn't build a message from the incoming data"); | 497 | m_log.Warn("[LLUDPSERVER]: Couldn't build a message from incoming data " + buffer.DataLength + |
498 | " bytes long from " + buffer.RemoteEndPoint); | ||
502 | return; | 499 | return; |
503 | } | 500 | } |
504 | 501 | ||
505 | //Stats.RecvBytes += (ulong)buffer.DataLength; | ||
506 | //++Stats.RecvPackets; | ||
507 | |||
508 | #endregion Decoding | 502 | #endregion Decoding |
509 | 503 | ||
510 | #region UseCircuitCode Handling | 504 | #region Packet to Client Mapping |
511 | 505 | ||
506 | // UseCircuitCode handling | ||
512 | if (packet.Type == PacketType.UseCircuitCode) | 507 | if (packet.Type == PacketType.UseCircuitCode) |
513 | { | 508 | { |
514 | UseCircuitCodePacket useCircuitCode = (UseCircuitCodePacket)packet; | 509 | 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 | } | 510 | } |
524 | 511 | ||
525 | // Determine which agent this packet came from | 512 | // Determine which agent this packet came from |
526 | if (!clients.TryGetValue(address, out client)) | 513 | IClientAPI client; |
514 | if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView)) | ||
527 | { | 515 | { |
528 | m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 516 | m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + |
517 | " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients"); | ||
529 | return; | 518 | return; |
530 | } | 519 | } |
531 | 520 | ||
532 | #endregion UseCircuitCode Handling | 521 | udpClient = ((LLClientView)client).UDPClient; |
522 | |||
523 | if (!udpClient.IsConnected) | ||
524 | return; | ||
525 | |||
526 | #endregion Packet to Client Mapping | ||
533 | 527 | ||
534 | // Stats tracking | 528 | // Stats tracking |
535 | Interlocked.Increment(ref client.PacketsReceived); | 529 | Interlocked.Increment(ref udpClient.PacketsReceived); |
536 | 530 | ||
537 | #region ACK Receiving | 531 | #region ACK Receiving |
538 | 532 | ||
539 | int now = Environment.TickCount; | 533 | int now = Environment.TickCount; |
540 | client.TickLastPacketReceived = now; | 534 | udpClient.TickLastPacketReceived = now; |
541 | 535 | ||
542 | // Handle appended ACKs | 536 | // Handle appended ACKs |
543 | if (packet.Header.AppendedAcks && packet.Header.AckList != null) | 537 | if (packet.Header.AppendedAcks && packet.Header.AckList != null) |
544 | { | 538 | { |
545 | lock (client.NeedAcks.SyncRoot) | 539 | lock (udpClient.NeedAcks.SyncRoot) |
546 | { | 540 | { |
547 | for (int i = 0; i < packet.Header.AckList.Length; i++) | 541 | for (int i = 0; i < packet.Header.AckList.Length; i++) |
548 | AcknowledgePacket(client, packet.Header.AckList[i], now, packet.Header.Resent); | 542 | AcknowledgePacket(udpClient, packet.Header.AckList[i], now, packet.Header.Resent); |
549 | } | 543 | } |
550 | } | 544 | } |
551 | 545 | ||
@@ -554,10 +548,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
554 | { | 548 | { |
555 | PacketAckPacket ackPacket = (PacketAckPacket)packet; | 549 | PacketAckPacket ackPacket = (PacketAckPacket)packet; |
556 | 550 | ||
557 | lock (client.NeedAcks.SyncRoot) | 551 | lock (udpClient.NeedAcks.SyncRoot) |
558 | { | 552 | { |
559 | for (int i = 0; i < ackPacket.Packets.Length; i++) | 553 | for (int i = 0; i < ackPacket.Packets.Length; i++) |
560 | AcknowledgePacket(client, ackPacket.Packets[i].ID, now, packet.Header.Resent); | 554 | AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent); |
561 | } | 555 | } |
562 | } | 556 | } |
563 | 557 | ||
@@ -566,27 +560,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
566 | #region ACK Sending | 560 | #region ACK Sending |
567 | 561 | ||
568 | if (packet.Header.Reliable) | 562 | if (packet.Header.Reliable) |
569 | client.PendingAcks.Enqueue((uint)packet.Header.Sequence); | 563 | udpClient.PendingAcks.Enqueue(packet.Header.Sequence); |
570 | 564 | ||
571 | // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, | 565 | // 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 | 566 | // 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 | 567 | // 2*MTU bytes from the value and send ACKs, and finally add the local value back to |
574 | // client.BytesSinceLastACK. Lockless thread safety | 568 | // client.BytesSinceLastACK. Lockless thread safety |
575 | int bytesSinceLastACK = Interlocked.Exchange(ref client.BytesSinceLastACK, 0); | 569 | int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); |
576 | bytesSinceLastACK += buffer.DataLength; | 570 | bytesSinceLastACK += buffer.DataLength; |
577 | if (bytesSinceLastACK > Packet.MTU * 2) | 571 | if (bytesSinceLastACK > Packet.MTU * 2) |
578 | { | 572 | { |
579 | bytesSinceLastACK -= Packet.MTU * 2; | 573 | bytesSinceLastACK -= Packet.MTU * 2; |
580 | SendAcks(client); | 574 | SendAcks(udpClient); |
581 | } | 575 | } |
582 | Interlocked.Add(ref client.BytesSinceLastACK, bytesSinceLastACK); | 576 | Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK); |
583 | 577 | ||
584 | #endregion ACK Sending | 578 | #endregion ACK Sending |
585 | 579 | ||
586 | #region Incoming Packet Accounting | 580 | #region Incoming Packet Accounting |
587 | 581 | ||
588 | // Check the archive of received reliable packet IDs to see whether we already received this packet | 582 | // 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)) | 583 | if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) |
590 | { | 584 | { |
591 | if (packet.Header.Resent) | 585 | if (packet.Header.Resent) |
592 | m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type); | 586 | m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type); |
@@ -603,7 +597,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
603 | if (packet.Type != PacketType.PacketAck) | 597 | if (packet.Type != PacketType.PacketAck) |
604 | { | 598 | { |
605 | // Inbox insertion | 599 | // Inbox insertion |
606 | packetInbox.Enqueue(new IncomingPacket(client, packet)); | 600 | packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); |
607 | } | 601 | } |
608 | } | 602 | } |
609 | 603 | ||
@@ -623,53 +617,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
623 | 617 | ||
624 | private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint) | 618 | private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint) |
625 | { | 619 | { |
626 | //Slave regions don't accept new clients | 620 | UUID agentID = useCircuitCode.CircuitCode.ID; |
621 | UUID sessionID = useCircuitCode.CircuitCode.SessionID; | ||
622 | uint circuitCode = useCircuitCode.CircuitCode.Code; | ||
623 | |||
627 | if (m_scene.RegionStatus != RegionStatus.SlaveScene) | 624 | if (m_scene.RegionStatus != RegionStatus.SlaveScene) |
628 | { | 625 | { |
629 | AuthenticateResponse sessionInfo; | 626 | AuthenticateResponse sessionInfo; |
630 | bool isNewCircuit = !clients.ContainsKey(remoteEndPoint); | 627 | if (IsClientAuthorized(useCircuitCode, out sessionInfo)) |
631 | |||
632 | if (!IsClientAuthorized(useCircuitCode, out sessionInfo)) | ||
633 | { | 628 | { |
634 | m_log.WarnFormat( | 629 | 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 | } | 630 | } |
639 | 631 | else | |
640 | if (isNewCircuit) | ||
641 | { | 632 | { |
642 | UUID agentID = useCircuitCode.CircuitCode.ID; | 633 | // Don't create circuits for unauthorized clients |
643 | UUID sessionID = useCircuitCode.CircuitCode.SessionID; | 634 | m_log.WarnFormat( |
644 | uint circuitCode = useCircuitCode.CircuitCode.Code; | 635 | "[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}", |
645 | 636 | useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint); | |
646 | AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo); | ||
647 | } | 637 | } |
648 | } | 638 | } |
639 | else | ||
640 | { | ||
641 | // Slave regions don't accept new clients | ||
642 | m_log.Debug("[LLUDPSERVER]: Slave region " + m_scene.RegionInfo.RegionName + " ignoring UseCircuitCode packet"); | ||
643 | } | ||
649 | } | 644 | } |
650 | 645 | ||
651 | private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) | 646 | private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) |
652 | { | 647 | { |
653 | // Create the LLUDPClient | 648 | // Create the LLUDPClient |
654 | LLUDPClient client = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint); | 649 | 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 | 650 | ||
666 | // Give LLUDPClient a reference to IClientAPI | 651 | if (!m_scene.ClientManager.ContainsKey(agentID)) |
667 | client.ClientAPI = clientApi; | 652 | { |
653 | // Create the LLClientView | ||
654 | LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); | ||
655 | client.OnLogout += LogoutHandler; | ||
668 | 656 | ||
669 | // Add the new client to our list of tracked clients | 657 | // Start the IClientAPI |
670 | clients.Add(agentID, client.RemoteEndPoint, client); | 658 | client.Start(); |
659 | } | ||
660 | else | ||
661 | { | ||
662 | m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}", | ||
663 | udpClient.AgentID, remoteEndPoint, circuitCode); | ||
664 | } | ||
665 | } | ||
671 | 666 | ||
672 | m_log.DebugFormat("[LLUDPSERVER]: Added new client {0} to region {1}", agentID, m_scene.RegionInfo.RegionName); | 667 | private void RemoveClient(LLUDPClient udpClient) |
668 | { | ||
669 | // Remove this client from the scene | ||
670 | IClientAPI client; | ||
671 | if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client)) | ||
672 | client.Close(); | ||
673 | } | 673 | } |
674 | 674 | ||
675 | private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend) | 675 | private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend) |
@@ -747,20 +747,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
747 | elapsed500MS = 0; | 747 | elapsed500MS = 0; |
748 | } | 748 | } |
749 | 749 | ||
750 | clients.ForEach( | 750 | m_scene.ClientManager.ForEach( |
751 | delegate(LLUDPClient client) | 751 | delegate(IClientAPI client) |
752 | { | 752 | { |
753 | if (client.DequeueOutgoing()) | 753 | if (client is LLClientView) |
754 | packetSent = true; | ||
755 | if (resendUnacked) | ||
756 | ResendUnacked(client); | ||
757 | if (sendAcks) | ||
758 | { | 754 | { |
759 | SendAcks(client); | 755 | LLUDPClient udpClient = ((LLClientView)client).UDPClient; |
760 | client.SendPacketStats(); | 756 | |
757 | if (udpClient.IsConnected) | ||
758 | { | ||
759 | if (udpClient.DequeueOutgoing()) | ||
760 | packetSent = true; | ||
761 | if (resendUnacked) | ||
762 | ResendUnacked(udpClient); | ||
763 | if (sendAcks) | ||
764 | { | ||
765 | SendAcks(udpClient); | ||
766 | udpClient.SendPacketStats(); | ||
767 | } | ||
768 | if (sendPings) | ||
769 | SendPing(udpClient); | ||
770 | } | ||
761 | } | 771 | } |
762 | if (sendPings) | ||
763 | SendPing(client); | ||
764 | } | 772 | } |
765 | ); | 773 | ); |
766 | 774 | ||
@@ -773,38 +781,48 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
773 | { | 781 | { |
774 | IncomingPacket incomingPacket = (IncomingPacket)state; | 782 | IncomingPacket incomingPacket = (IncomingPacket)state; |
775 | Packet packet = incomingPacket.Packet; | 783 | Packet packet = incomingPacket.Packet; |
776 | LLUDPClient client = incomingPacket.Client; | 784 | LLUDPClient udpClient = incomingPacket.Client; |
785 | IClientAPI client; | ||
777 | 786 | ||
778 | // Sanity check | 787 | // Sanity check |
779 | if (packet == null || client == null || client.ClientAPI == null) | 788 | if (packet == null || udpClient == null) |
780 | { | 789 | { |
781 | m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", Client=\"{1}\", Client.ClientAPI=\"{2}\"", | 790 | m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"", |
782 | packet, client, (client != null) ? client.ClientAPI : null); | 791 | packet, udpClient); |
783 | } | 792 | } |
784 | 793 | ||
785 | try | 794 | // Make sure this client is still alive |
786 | { | 795 | if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client)) |
787 | // Process this packet | ||
788 | client.ClientAPI.ProcessInPacket(packet); | ||
789 | } | ||
790 | catch (ThreadAbortException) | ||
791 | { | 796 | { |
792 | // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down | 797 | try |
793 | m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); | 798 | { |
794 | Stop(); | 799 | // Process this packet |
800 | client.ProcessInPacket(packet); | ||
801 | } | ||
802 | catch (ThreadAbortException) | ||
803 | { | ||
804 | // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down | ||
805 | m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); | ||
806 | Stop(); | ||
807 | } | ||
808 | catch (Exception e) | ||
809 | { | ||
810 | // Don't let a failure in an individual client thread crash the whole sim. | ||
811 | m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type); | ||
812 | m_log.Error(e.Message, e); | ||
813 | } | ||
795 | } | 814 | } |
796 | catch (Exception e) | 815 | else |
797 | { | 816 | { |
798 | // Don't let a failure in an individual client thread crash the whole sim. | 817 | 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 | } | 818 | } |
802 | } | 819 | } |
803 | 820 | ||
804 | private void LogoutHandler(IClientAPI client) | 821 | private void LogoutHandler(IClientAPI client) |
805 | { | 822 | { |
806 | client.SendLogoutPacket(); | 823 | client.SendLogoutPacket(); |
807 | RemoveClient(client); | 824 | if (client.IsActive) |
825 | RemoveClient(((LLClientView)client).UDPClient); | ||
808 | } | 826 | } |
809 | } | 827 | } |
810 | } | 828 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs index 43a68ec..d16837d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs | |||
@@ -1,419 +1,137 @@ | |||
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; |
58 | |||
59 | /// <summary>Local IP address to bind to in server mode</summary> | ||
60 | protected IPAddress m_localBindAddress; | ||
360 | 61 | ||
361 | // the UDP socket | 62 | /// <summary>UDP socket, used in either client or server mode</summary> |
362 | private Socket udpSocket; | 63 | private Socket m_udpSocket; |
363 | 64 | ||
364 | // the all important shutdownFlag. | 65 | /// <summary>Flag to process packets asynchronously or synchronously</summary> |
365 | private volatile bool shutdownFlag = true; | 66 | private bool m_asyncPacketHandling; |
366 | 67 | ||
367 | // the remote endpoint to communicate with | 68 | /// <summary>The all important shutdown flag</summary> |
368 | protected IPEndPoint remoteEndPoint = null; | 69 | private volatile bool m_shutdownFlag = true; |
70 | |||
71 | /// <summary>Returns true if the server is currently listening, otherwise false</summary> | ||
72 | public bool IsRunning { get { return !m_shutdownFlag; } } | ||
369 | 73 | ||
370 | /// <summary> | 74 | /// <summary> |
371 | /// Initialize the UDP packet handler in server mode | 75 | /// Default constructor |
372 | /// </summary> | 76 | /// </summary> |
77 | /// <param name="bindAddress">Local IP address to bind the server to</param> | ||
373 | /// <param name="port">Port to listening for incoming UDP packets on</param> | 78 | /// <param name="port">Port to listening for incoming UDP packets on</param> |
374 | public OpenSimUDPBase(int port) | 79 | public OpenSimUDPBase(IPAddress bindAddress, int port) |
375 | { | 80 | { |
376 | udpPort = port; | 81 | m_localBindAddress = bindAddress; |
82 | m_udpPort = port; | ||
377 | } | 83 | } |
378 | 84 | ||
379 | /// <summary> | 85 | /// <summary> |
380 | /// Initialize the UDP packet handler in client mode | 86 | /// Start the UDP server |
381 | /// </summary> | 87 | /// </summary> |
382 | /// <param name="endPoint">Remote UDP server to connect to</param> | 88 | /// <param name="recvBufferSize">The size of the receive buffer for |
383 | public OpenSimUDPBase(IPEndPoint endPoint) | 89 | /// the UDP socket. This value is passed up to the operating system |
90 | /// and used in the system networking stack. Use zero to leave this | ||
91 | /// value as the default</param> | ||
92 | /// <param name="asyncPacketHandling">Set this to true to start | ||
93 | /// receiving more packets while current packet handler callbacks are | ||
94 | /// still running. Setting this to false will complete each packet | ||
95 | /// callback before the next packet is processed</param> | ||
96 | /// <remarks>This method will attempt to set the SIO_UDP_CONNRESET flag | ||
97 | /// on the socket to get newer versions of Windows to behave in a sane | ||
98 | /// manner (not throwing an exception when the remote side resets the | ||
99 | /// connection). This call is ignored on Mono where the flag is not | ||
100 | /// necessary</remarks> | ||
101 | public void Start(int recvBufferSize, bool asyncPacketHandling) | ||
384 | { | 102 | { |
385 | remoteEndPoint = endPoint; | 103 | m_asyncPacketHandling = asyncPacketHandling; |
386 | udpPort = 0; | ||
387 | } | ||
388 | 104 | ||
389 | /// <summary> | 105 | if (m_shutdownFlag) |
390 | /// | ||
391 | /// </summary> | ||
392 | public void Start() | ||
393 | { | ||
394 | if (shutdownFlag) | ||
395 | { | 106 | { |
396 | const int SIO_UDP_CONNRESET = -1744830452; | 107 | const int SIO_UDP_CONNRESET = -1744830452; |
397 | 108 | ||
398 | IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); | 109 | IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); |
399 | udpSocket = new Socket( | 110 | |
111 | m_udpSocket = new Socket( | ||
400 | AddressFamily.InterNetwork, | 112 | AddressFamily.InterNetwork, |
401 | SocketType.Dgram, | 113 | SocketType.Dgram, |
402 | ProtocolType.Udp); | 114 | ProtocolType.Udp); |
115 | |||
403 | try | 116 | try |
404 | { | 117 | { |
405 | // this udp socket flag is not supported under mono, | 118 | // This udp socket flag is not supported under mono, |
406 | // so we'll catch the exception and continue | 119 | // so we'll catch the exception and continue |
407 | udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); | 120 | m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); |
121 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set"); | ||
408 | } | 122 | } |
409 | catch (SocketException) | 123 | catch (SocketException) |
410 | { | 124 | { |
411 | Logger.DebugLog("UDP SIO_UDP_CONNRESET flag not supported on this platform"); | 125 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); |
412 | } | 126 | } |
413 | udpSocket.Bind(ipep); | 127 | |
128 | if (recvBufferSize != 0) | ||
129 | m_udpSocket.ReceiveBufferSize = recvBufferSize; | ||
130 | |||
131 | m_udpSocket.Bind(ipep); | ||
414 | 132 | ||
415 | // we're not shutting down, we're starting up | 133 | // we're not shutting down, we're starting up |
416 | shutdownFlag = false; | 134 | m_shutdownFlag = false; |
417 | 135 | ||
418 | // kick off an async receive. The Start() method will return, the | 136 | // kick off an async receive. The Start() method will return, the |
419 | // actual receives will occur asynchronously and will be caught in | 137 | // actual receives will occur asynchronously and will be caught in |
@@ -423,41 +141,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
423 | } | 141 | } |
424 | 142 | ||
425 | /// <summary> | 143 | /// <summary> |
426 | /// | 144 | /// Stops the UDP server |
427 | /// </summary> | 145 | /// </summary> |
428 | public void Stop() | 146 | public void Stop() |
429 | { | 147 | { |
430 | if (!shutdownFlag) | 148 | if (!m_shutdownFlag) |
431 | { | 149 | { |
432 | // wait indefinitely for a writer lock. Once this is called, the .NET runtime | 150 | // 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 | 151 | // 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 | 152 | // threads. Once we have the lock, we set shutdownFlag to inform the other |
435 | // threads that the socket is closed. | 153 | // threads that the socket is closed. |
436 | shutdownFlag = true; | 154 | m_shutdownFlag = true; |
437 | udpSocket.Close(); | 155 | m_udpSocket.Close(); |
438 | } | 156 | } |
439 | } | 157 | } |
440 | 158 | ||
441 | /// <summary> | ||
442 | /// | ||
443 | /// </summary> | ||
444 | public bool IsRunning | ||
445 | { | ||
446 | get { return !shutdownFlag; } | ||
447 | } | ||
448 | |||
449 | private void AsyncBeginReceive() | 159 | private void AsyncBeginReceive() |
450 | { | 160 | { |
451 | // allocate a packet buffer | 161 | // allocate a packet buffer |
452 | //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); | 162 | //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); |
453 | UDPPacketBuffer buf = new UDPPacketBuffer(); | 163 | UDPPacketBuffer buf = new UDPPacketBuffer(); |
454 | 164 | ||
455 | if (!shutdownFlag) | 165 | if (!m_shutdownFlag) |
456 | { | 166 | { |
457 | try | 167 | try |
458 | { | 168 | { |
459 | // kick off an async read | 169 | // kick off an async read |
460 | udpSocket.BeginReceiveFrom( | 170 | m_udpSocket.BeginReceiveFrom( |
461 | //wrappedBuffer.Instance.Data, | 171 | //wrappedBuffer.Instance.Data, |
462 | buf.Data, | 172 | buf.Data, |
463 | 0, | 173 | 0, |
@@ -472,13 +182,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
472 | { | 182 | { |
473 | if (e.SocketErrorCode == SocketError.ConnectionReset) | 183 | if (e.SocketErrorCode == SocketError.ConnectionReset) |
474 | { | 184 | { |
475 | Logger.Log("SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + udpPort, Helpers.LogLevel.Error); | 185 | m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort); |
476 | bool salvaged = false; | 186 | bool salvaged = false; |
477 | while (!salvaged) | 187 | while (!salvaged) |
478 | { | 188 | { |
479 | try | 189 | try |
480 | { | 190 | { |
481 | udpSocket.BeginReceiveFrom( | 191 | m_udpSocket.BeginReceiveFrom( |
482 | //wrappedBuffer.Instance.Data, | 192 | //wrappedBuffer.Instance.Data, |
483 | buf.Data, | 193 | buf.Data, |
484 | 0, | 194 | 0, |
@@ -494,7 +204,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
494 | catch (ObjectDisposedException) { return; } | 204 | catch (ObjectDisposedException) { return; } |
495 | } | 205 | } |
496 | 206 | ||
497 | Logger.Log("Salvaged the UDP listener on port " + udpPort, Helpers.LogLevel.Info); | 207 | m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); |
498 | } | 208 | } |
499 | } | 209 | } |
500 | catch (ObjectDisposedException) { } | 210 | catch (ObjectDisposedException) { } |
@@ -505,10 +215,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
505 | { | 215 | { |
506 | // Asynchronous receive operations will complete here through the call | 216 | // Asynchronous receive operations will complete here through the call |
507 | // to AsyncBeginReceive | 217 | // to AsyncBeginReceive |
508 | if (!shutdownFlag) | 218 | if (!m_shutdownFlag) |
509 | { | 219 | { |
510 | // start another receive - this keeps the server going! | 220 | // Asynchronous mode will start another receive before the |
511 | AsyncBeginReceive(); | 221 | // callback for this packet is even fired. Very parallel :-) |
222 | if (m_asyncPacketHandling) | ||
223 | AsyncBeginReceive(); | ||
512 | 224 | ||
513 | // get the buffer that was created in AsyncBeginReceive | 225 | // get the buffer that was created in AsyncBeginReceive |
514 | // this is the received data | 226 | // this is the received data |
@@ -520,7 +232,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
520 | { | 232 | { |
521 | // get the length of data actually read from the socket, store it with the | 233 | // get the length of data actually read from the socket, store it with the |
522 | // buffer | 234 | // buffer |
523 | buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); | 235 | buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); |
524 | 236 | ||
525 | // call the abstract method PacketReceived(), passing the buffer that | 237 | // call the abstract method PacketReceived(), passing the buffer that |
526 | // has just been filled from the socket read. | 238 | // has just been filled from the socket read. |
@@ -528,17 +240,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
528 | } | 240 | } |
529 | catch (SocketException) { } | 241 | catch (SocketException) { } |
530 | catch (ObjectDisposedException) { } | 242 | catch (ObjectDisposedException) { } |
531 | //finally { wrappedBuffer.Dispose(); } | 243 | finally |
244 | { | ||
245 | //wrappedBuffer.Dispose(); | ||
246 | |||
247 | // Synchronous mode waits until the packet callback completes | ||
248 | // before starting the receive to fetch another packet | ||
249 | if (!m_asyncPacketHandling) | ||
250 | AsyncBeginReceive(); | ||
251 | } | ||
252 | |||
532 | } | 253 | } |
533 | } | 254 | } |
534 | 255 | ||
535 | public void AsyncBeginSend(UDPPacketBuffer buf) | 256 | public void AsyncBeginSend(UDPPacketBuffer buf) |
536 | { | 257 | { |
537 | if (!shutdownFlag) | 258 | if (!m_shutdownFlag) |
538 | { | 259 | { |
539 | try | 260 | try |
540 | { | 261 | { |
541 | udpSocket.BeginSendTo( | 262 | m_udpSocket.BeginSendTo( |
542 | buf.Data, | 263 | buf.Data, |
543 | 0, | 264 | 0, |
544 | buf.DataLength, | 265 | buf.DataLength, |
@@ -557,7 +278,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
557 | try | 278 | try |
558 | { | 279 | { |
559 | UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; | 280 | UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; |
560 | int bytesSent = udpSocket.EndSendTo(result); | 281 | int bytesSent = m_udpSocket.EndSendTo(result); |
561 | 282 | ||
562 | PacketSent(buf, bytesSent); | 283 | PacketSent(buf, bytesSent); |
563 | } | 284 | } |
@@ -566,4 +287,3 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
566 | } | 287 | } |
567 | } | 288 | } |
568 | } | 289 | } |
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/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index b81ab41..4041b63 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs | |||
@@ -43,6 +43,7 @@ using Mono.Addins; | |||
43 | using OpenMetaverse; | 43 | using OpenMetaverse; |
44 | 44 | ||
45 | using OpenSim.Framework; | 45 | using OpenSim.Framework; |
46 | using OpenSim.Framework.Console; | ||
46 | using OpenSim.Region.Framework.Interfaces; | 47 | using OpenSim.Region.Framework.Interfaces; |
47 | using OpenSim.Region.Framework.Scenes; | 48 | using OpenSim.Region.Framework.Scenes; |
48 | using OpenSim.Services.Interfaces; | 49 | using OpenSim.Services.Interfaces; |
@@ -54,7 +55,7 @@ using OpenSim.Services.Interfaces; | |||
54 | namespace Flotsam.RegionModules.AssetCache | 55 | namespace Flotsam.RegionModules.AssetCache |
55 | { | 56 | { |
56 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | 57 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] |
57 | public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache | 58 | public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache, IAssetService |
58 | { | 59 | { |
59 | private static readonly ILog m_log = | 60 | private static readonly ILog m_log = |
60 | LogManager.GetLogger( | 61 | LogManager.GetLogger( |
@@ -102,6 +103,11 @@ namespace Flotsam.RegionModules.AssetCache | |||
102 | 103 | ||
103 | private System.Timers.Timer m_CachCleanTimer = new System.Timers.Timer(); | 104 | private System.Timers.Timer m_CachCleanTimer = new System.Timers.Timer(); |
104 | 105 | ||
106 | private IAssetService m_AssetService = null; | ||
107 | private List<Scene> m_Scenes = new List<Scene>(); | ||
108 | |||
109 | private bool m_DeepScanBeforePurge = false; | ||
110 | |||
105 | public FlotsamAssetCache() | 111 | public FlotsamAssetCache() |
106 | { | 112 | { |
107 | m_InvalidChars.AddRange(Path.GetInvalidPathChars()); | 113 | m_InvalidChars.AddRange(Path.GetInvalidPathChars()); |
@@ -121,6 +127,7 @@ namespace Flotsam.RegionModules.AssetCache | |||
121 | public void Initialise(IConfigSource source) | 127 | public void Initialise(IConfigSource source) |
122 | { | 128 | { |
123 | IConfig moduleConfig = source.Configs["Modules"]; | 129 | IConfig moduleConfig = source.Configs["Modules"]; |
130 | |||
124 | 131 | ||
125 | if (moduleConfig != null) | 132 | if (moduleConfig != null) |
126 | { | 133 | { |
@@ -195,7 +202,13 @@ namespace Flotsam.RegionModules.AssetCache | |||
195 | 202 | ||
196 | m_CacheWarnAt = assetConfig.GetInt("CacheWarnAt", 30000); | 203 | m_CacheWarnAt = assetConfig.GetInt("CacheWarnAt", 30000); |
197 | 204 | ||
198 | 205 | m_DeepScanBeforePurge = assetConfig.GetBoolean("DeepScanBeforePurge", false); | |
206 | |||
207 | MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache status", "fcache status", "Display cache status", HandleConsoleCommand); | ||
208 | MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache clear", "fcache clear [file] [memory]", "Remove all assets in the file and/or memory cache", HandleConsoleCommand); | ||
209 | MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache assets", "fcache assets", "Attempt a deep scan and cache of all assets in all scenes", HandleConsoleCommand); | ||
210 | MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache expire", "fcache expire <datetime>", "Purge cached assets older then the specified date/time", HandleConsoleCommand); | ||
211 | |||
199 | } | 212 | } |
200 | } | 213 | } |
201 | } | 214 | } |
@@ -213,16 +226,23 @@ namespace Flotsam.RegionModules.AssetCache | |||
213 | if (m_Enabled) | 226 | if (m_Enabled) |
214 | { | 227 | { |
215 | scene.RegisterModuleInterface<IImprovedAssetCache>(this); | 228 | scene.RegisterModuleInterface<IImprovedAssetCache>(this); |
229 | m_Scenes.Add(scene); | ||
216 | 230 | ||
217 | //scene.AddCommand(this, "flotsamcache", "", "Display a list of console commands for the Flotsam Asset Cache", HandleConsoleCommand); | 231 | if (m_AssetService == null) |
218 | scene.AddCommand(this, "flotsamcache counts", "flotsamcache counts", "Display the number of cached assets", HandleConsoleCommand); | 232 | { |
219 | scene.AddCommand(this, "flotsamcache clearmem", "flotsamcache clearmem", "Remove all assets cached in memory", HandleConsoleCommand); | 233 | m_AssetService = scene.RequestModuleInterface<IAssetService>(); |
220 | scene.AddCommand(this, "flotsamcache clearfile", "flotsamcache clearfile", "Remove all assets cached on disk", HandleConsoleCommand); | 234 | |
235 | } | ||
221 | } | 236 | } |
222 | } | 237 | } |
223 | 238 | ||
224 | public void RemoveRegion(Scene scene) | 239 | public void RemoveRegion(Scene scene) |
225 | { | 240 | { |
241 | if (m_Enabled) | ||
242 | { | ||
243 | scene.UnregisterModuleInterface<IImprovedAssetCache>(this); | ||
244 | m_Scenes.Remove(scene); | ||
245 | } | ||
226 | } | 246 | } |
227 | 247 | ||
228 | public void RegionLoaded(Scene scene) | 248 | public void RegionLoaded(Scene scene) |
@@ -442,31 +462,47 @@ namespace Flotsam.RegionModules.AssetCache | |||
442 | if (m_LogLevel >= 2) | 462 | if (m_LogLevel >= 2) |
443 | m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Checking for expired files older then {0}.", m_FileExpiration.ToString()); | 463 | m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Checking for expired files older then {0}.", m_FileExpiration.ToString()); |
444 | 464 | ||
465 | // Purge all files last accessed prior to this point | ||
466 | DateTime purgeLine = DateTime.Now - m_FileExpiration; | ||
467 | |||
468 | // An optional deep scan at this point will ensure assets present in scenes, | ||
469 | // or referenced by objects in the scene, but not recently accessed | ||
470 | // are not purged. | ||
471 | if (m_DeepScanBeforePurge) | ||
472 | { | ||
473 | CacheScenes(); | ||
474 | } | ||
475 | |||
445 | foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) | 476 | foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) |
446 | { | 477 | { |
447 | CleanExpiredFiles(dir); | 478 | CleanExpiredFiles(dir, purgeLine); |
448 | } | 479 | } |
449 | } | 480 | } |
450 | 481 | ||
451 | /// <summary> | 482 | /// <summary> |
452 | /// Recurses through specified directory checking for expired asset files and deletes them. Also removes empty directories. | 483 | /// Recurses through specified directory checking for asset files last |
484 | /// accessed prior to the specified purge line and deletes them. Also | ||
485 | /// removes empty tier directories. | ||
453 | /// </summary> | 486 | /// </summary> |
454 | /// <param name="dir"></param> | 487 | /// <param name="dir"></param> |
455 | private void CleanExpiredFiles(string dir) | 488 | private void CleanExpiredFiles(string dir, DateTime purgeLine) |
456 | { | 489 | { |
490 | |||
457 | foreach (string file in Directory.GetFiles(dir)) | 491 | foreach (string file in Directory.GetFiles(dir)) |
458 | { | 492 | { |
459 | if (DateTime.Now - File.GetLastAccessTime(file) > m_FileExpiration) | 493 | if (File.GetLastAccessTime(file) < purgeLine) |
460 | { | 494 | { |
461 | File.Delete(file); | 495 | File.Delete(file); |
462 | } | 496 | } |
463 | } | 497 | } |
464 | 498 | ||
499 | // Recurse into lower tiers | ||
465 | foreach (string subdir in Directory.GetDirectories(dir)) | 500 | foreach (string subdir in Directory.GetDirectories(dir)) |
466 | { | 501 | { |
467 | CleanExpiredFiles(subdir); | 502 | CleanExpiredFiles(subdir, purgeLine); |
468 | } | 503 | } |
469 | 504 | ||
505 | // Check if a tier directory is empty, if so, delete it | ||
470 | int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length; | 506 | int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length; |
471 | if (dirSize == 0) | 507 | if (dirSize == 0) |
472 | { | 508 | { |
@@ -478,6 +514,11 @@ namespace Flotsam.RegionModules.AssetCache | |||
478 | } | 514 | } |
479 | } | 515 | } |
480 | 516 | ||
517 | /// <summary> | ||
518 | /// Determines the filename for an AssetID stored in the file cache | ||
519 | /// </summary> | ||
520 | /// <param name="id"></param> | ||
521 | /// <returns></returns> | ||
481 | private string GetFileName(string id) | 522 | private string GetFileName(string id) |
482 | { | 523 | { |
483 | // Would it be faster to just hash the darn thing? | 524 | // Would it be faster to just hash the darn thing? |
@@ -496,14 +537,23 @@ namespace Flotsam.RegionModules.AssetCache | |||
496 | return Path.Combine(path, id); | 537 | return Path.Combine(path, id); |
497 | } | 538 | } |
498 | 539 | ||
540 | /// <summary> | ||
541 | /// Writes a file to the file cache, creating any nessesary | ||
542 | /// tier directories along the way | ||
543 | /// </summary> | ||
544 | /// <param name="filename"></param> | ||
545 | /// <param name="asset"></param> | ||
499 | private void WriteFileCache(string filename, AssetBase asset) | 546 | private void WriteFileCache(string filename, AssetBase asset) |
500 | { | 547 | { |
501 | Stream stream = null; | 548 | Stream stream = null; |
549 | |||
502 | // Make sure the target cache directory exists | 550 | // Make sure the target cache directory exists |
503 | string directory = Path.GetDirectoryName(filename); | 551 | string directory = Path.GetDirectoryName(filename); |
552 | |||
504 | // Write file first to a temp name, so that it doesn't look | 553 | // Write file first to a temp name, so that it doesn't look |
505 | // like it's already cached while it's still writing. | 554 | // like it's already cached while it's still writing. |
506 | string tempname = Path.Combine(directory, Path.GetRandomFileName()); | 555 | string tempname = Path.Combine(directory, Path.GetRandomFileName()); |
556 | |||
507 | try | 557 | try |
508 | { | 558 | { |
509 | if (!Directory.Exists(directory)) | 559 | if (!Directory.Exists(directory)) |
@@ -563,6 +613,11 @@ namespace Flotsam.RegionModules.AssetCache | |||
563 | } | 613 | } |
564 | } | 614 | } |
565 | 615 | ||
616 | /// <summary> | ||
617 | /// Scan through the file cache, and return number of assets currently cached. | ||
618 | /// </summary> | ||
619 | /// <param name="dir"></param> | ||
620 | /// <returns></returns> | ||
566 | private int GetFileCacheCount(string dir) | 621 | private int GetFileCacheCount(string dir) |
567 | { | 622 | { |
568 | int count = Directory.GetFiles(dir).Length; | 623 | int count = Directory.GetFiles(dir).Length; |
@@ -575,55 +630,180 @@ namespace Flotsam.RegionModules.AssetCache | |||
575 | return count; | 630 | return count; |
576 | } | 631 | } |
577 | 632 | ||
633 | /// <summary> | ||
634 | /// This notes the last time the Region had a deep asset scan performed on it. | ||
635 | /// </summary> | ||
636 | /// <param name="RegionID"></param> | ||
637 | private void StampRegionStatusFile(UUID RegionID) | ||
638 | { | ||
639 | string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + RegionID.ToString() + ".fac"); | ||
640 | if (File.Exists(RegionCacheStatusFile)) | ||
641 | { | ||
642 | File.SetLastWriteTime(RegionCacheStatusFile, DateTime.Now); | ||
643 | } | ||
644 | else | ||
645 | { | ||
646 | File.WriteAllText(RegionCacheStatusFile, "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache."); | ||
647 | } | ||
648 | } | ||
649 | |||
650 | /// <summary> | ||
651 | /// Iterates through all Scenes, doing a deep scan through assets | ||
652 | /// to cache all assets present in the scene or referenced by assets | ||
653 | /// in the scene | ||
654 | /// </summary> | ||
655 | /// <returns></returns> | ||
656 | private int CacheScenes() | ||
657 | { | ||
658 | UuidGatherer gatherer = new UuidGatherer(m_AssetService); | ||
659 | |||
660 | Dictionary<UUID, int> assets = new Dictionary<UUID, int>(); | ||
661 | foreach (Scene s in m_Scenes) | ||
662 | { | ||
663 | StampRegionStatusFile(s.RegionInfo.RegionID); | ||
664 | |||
665 | s.ForEachSOG(delegate(SceneObjectGroup e) | ||
666 | { | ||
667 | gatherer.GatherAssetUuids(e, assets); | ||
668 | } | ||
669 | ); | ||
670 | } | ||
671 | |||
672 | foreach (UUID assetID in assets.Keys) | ||
673 | { | ||
674 | string filename = GetFileName(assetID.ToString()); | ||
675 | |||
676 | if (File.Exists(filename)) | ||
677 | { | ||
678 | File.SetLastAccessTime(filename, DateTime.Now); | ||
679 | } | ||
680 | else | ||
681 | { | ||
682 | m_AssetService.Get(assetID.ToString()); | ||
683 | } | ||
684 | } | ||
685 | |||
686 | return assets.Keys.Count; | ||
687 | } | ||
688 | |||
689 | /// <summary> | ||
690 | /// Deletes all cache contents | ||
691 | /// </summary> | ||
692 | private void ClearFileCache() | ||
693 | { | ||
694 | foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) | ||
695 | { | ||
696 | try | ||
697 | { | ||
698 | Directory.Delete(dir, true); | ||
699 | } | ||
700 | catch (Exception e) | ||
701 | { | ||
702 | LogException(e); | ||
703 | } | ||
704 | } | ||
705 | |||
706 | foreach (string file in Directory.GetFiles(m_CacheDirectory)) | ||
707 | { | ||
708 | try | ||
709 | { | ||
710 | File.Delete(file); | ||
711 | } | ||
712 | catch (Exception e) | ||
713 | { | ||
714 | LogException(e); | ||
715 | } | ||
716 | } | ||
717 | } | ||
718 | |||
578 | #region Console Commands | 719 | #region Console Commands |
579 | private void HandleConsoleCommand(string module, string[] cmdparams) | 720 | private void HandleConsoleCommand(string module, string[] cmdparams) |
580 | { | 721 | { |
581 | if (cmdparams.Length == 2) | 722 | if (cmdparams.Length >= 2) |
582 | { | 723 | { |
583 | string cmd = cmdparams[1]; | 724 | string cmd = cmdparams[1]; |
584 | switch (cmd) | 725 | switch (cmd) |
585 | { | 726 | { |
586 | case "count": | 727 | case "status": |
587 | case "counts": | 728 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] Memory Cache : {0} assets", m_MemoryCache.Count); |
588 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] Memory Cache : {0}", m_MemoryCache.Count); | ||
589 | 729 | ||
590 | int fileCount = GetFileCacheCount(m_CacheDirectory); | 730 | int fileCount = GetFileCacheCount(m_CacheDirectory); |
591 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] File Cache : {0}", fileCount); | 731 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] File Cache : {0} assets", fileCount); |
592 | 732 | ||
593 | break; | 733 | foreach ( string s in Directory.GetFiles(m_CacheDirectory, "*.fac" ) ) |
734 | { | ||
735 | m_log.Info("[FLOTSAM ASSET CACHE] Deep Scans were performed on the following regions:"); | ||
736 | |||
737 | string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac",""); | ||
738 | DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s); | ||
739 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss")); | ||
740 | } | ||
594 | 741 | ||
595 | case "clearmem": | ||
596 | m_MemoryCache.Clear(); | ||
597 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] Memory Cache Cleared, there are now {0} items in the memory cache", m_MemoryCache.Count); | ||
598 | break; | 742 | break; |
599 | 743 | ||
600 | case "clearfile": | 744 | case "clear": |
601 | foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) | 745 | if (cmdparams.Length < 3) |
602 | { | 746 | { |
603 | try | 747 | m_log.Warn("[FLOTSAM ASSET CACHE] Please specify memory and/or file cache."); |
604 | { | 748 | break; |
605 | Directory.Delete(dir, true); | ||
606 | } | ||
607 | catch (Exception e) | ||
608 | { | ||
609 | LogException(e); | ||
610 | } | ||
611 | } | 749 | } |
612 | 750 | foreach (string s in cmdparams) | |
613 | foreach (string file in Directory.GetFiles(m_CacheDirectory)) | ||
614 | { | 751 | { |
615 | try | 752 | if (s.ToLower() == "memory") |
616 | { | 753 | { |
617 | File.Delete(file); | 754 | m_MemoryCache.Clear(); |
755 | m_log.Info("[FLOTSAM ASSET CACHE] Memory cache cleared."); | ||
618 | } | 756 | } |
619 | catch (Exception e) | 757 | else if (s.ToLower() == "file") |
620 | { | 758 | { |
621 | LogException(e); | 759 | ClearFileCache(); |
760 | m_log.Info("[FLOTSAM ASSET CACHE] File cache cleared."); | ||
622 | } | 761 | } |
623 | } | 762 | } |
763 | break; | ||
764 | |||
765 | |||
766 | case "assets": | ||
767 | m_log.Info("[FLOTSAM ASSET CACHE] Caching all assets, in all scenes."); | ||
768 | |||
769 | Util.FireAndForget(delegate { | ||
770 | int assetsCached = CacheScenes(); | ||
771 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] Completed Scene Caching, {0} assets found.", assetsCached); | ||
772 | |||
773 | }); | ||
624 | 774 | ||
625 | break; | 775 | break; |
626 | 776 | ||
777 | case "expire": | ||
778 | |||
779 | |||
780 | if (cmdparams.Length >= 3) | ||
781 | { | ||
782 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] Invalid parameters for Expire, please specify a valid date & time", cmd); | ||
783 | break; | ||
784 | } | ||
785 | |||
786 | string s_expirationDate = ""; | ||
787 | DateTime expirationDate; | ||
788 | |||
789 | if (cmdparams.Length > 3) | ||
790 | { | ||
791 | s_expirationDate = string.Join(" ", cmdparams, 2, cmdparams.Length - 2); | ||
792 | } | ||
793 | else | ||
794 | { | ||
795 | s_expirationDate = cmdparams[2]; | ||
796 | } | ||
797 | |||
798 | if (!DateTime.TryParse(s_expirationDate, out expirationDate)) | ||
799 | { | ||
800 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] {0} is not a valid date & time", cmd); | ||
801 | break; | ||
802 | } | ||
803 | |||
804 | CleanExpiredFiles(m_CacheDirectory, expirationDate); | ||
805 | |||
806 | break; | ||
627 | default: | 807 | default: |
628 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] Unknown command {0}", cmd); | 808 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] Unknown command {0}", cmd); |
629 | break; | 809 | break; |
@@ -631,13 +811,66 @@ namespace Flotsam.RegionModules.AssetCache | |||
631 | } | 811 | } |
632 | else if (cmdparams.Length == 1) | 812 | else if (cmdparams.Length == 1) |
633 | { | 813 | { |
634 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache counts - Display the number of cached assets"); | 814 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache status - Display cache status"); |
635 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearmem - Remove all assets cached in memory"); | 815 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearmem - Remove all assets cached in memory"); |
636 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearfile - Remove all assets cached on disk"); | 816 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearfile - Remove all assets cached on disk"); |
817 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache cachescenes - Attempt a deep cache of all assets in all scenes"); | ||
818 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache <datetime> - Purge assets older then the specified date & time"); | ||
637 | 819 | ||
638 | } | 820 | } |
639 | } | 821 | } |
640 | 822 | ||
641 | #endregion | 823 | #endregion |
824 | |||
825 | #region IAssetService Members | ||
826 | |||
827 | |||
828 | public AssetMetadata GetMetadata(string id) | ||
829 | { | ||
830 | AssetBase asset = Get(id); | ||
831 | return asset.Metadata; | ||
832 | } | ||
833 | |||
834 | public byte[] GetData(string id) | ||
835 | { | ||
836 | AssetBase asset = Get(id); | ||
837 | return asset.Data; | ||
838 | } | ||
839 | |||
840 | public bool Get(string id, object sender, AssetRetrieved handler) | ||
841 | { | ||
842 | AssetBase asset = Get(id); | ||
843 | handler(id, sender, asset); | ||
844 | return true; | ||
845 | } | ||
846 | |||
847 | public string Store(AssetBase asset) | ||
848 | { | ||
849 | if ((asset.FullID == null) || (asset.FullID == UUID.Zero)) | ||
850 | { | ||
851 | asset.FullID = UUID.Random(); | ||
852 | } | ||
853 | |||
854 | Cache(asset); | ||
855 | |||
856 | return asset.ID; | ||
857 | |||
858 | } | ||
859 | |||
860 | public bool UpdateContent(string id, byte[] data) | ||
861 | { | ||
862 | AssetBase asset = Get(id); | ||
863 | asset.Data = data; | ||
864 | Cache(asset); | ||
865 | return true; | ||
866 | } | ||
867 | |||
868 | public bool Delete(string id) | ||
869 | { | ||
870 | Expire(id); | ||
871 | return true; | ||
872 | } | ||
873 | |||
874 | #endregion | ||
642 | } | 875 | } |
643 | } \ No newline at end of file | 876 | } \ No newline at end of file |
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/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs index 7b4e374..0aa753d 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs | |||
@@ -31,6 +31,7 @@ using System; | |||
31 | using System.Collections.Generic; | 31 | using System.Collections.Generic; |
32 | using System.Reflection; | 32 | using System.Reflection; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Communications.Cache; | ||
34 | using OpenSim.Server.Base; | 35 | using OpenSim.Server.Base; |
35 | using OpenSim.Region.Framework.Interfaces; | 36 | using OpenSim.Region.Framework.Interfaces; |
36 | using OpenSim.Region.Framework.Scenes; | 37 | using OpenSim.Region.Framework.Scenes; |
@@ -40,7 +41,7 @@ using OpenMetaverse; | |||
40 | namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset | 41 | namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset |
41 | { | 42 | { |
42 | public class HGAssetBroker : | 43 | public class HGAssetBroker : |
43 | ISharedRegionModule, IAssetService | 44 | ISharedRegionModule, IAssetService, IHyperAssetService |
44 | { | 45 | { |
45 | private static readonly ILog m_log = | 46 | private static readonly ILog m_log = |
46 | LogManager.GetLogger( | 47 | LogManager.GetLogger( |
@@ -50,6 +51,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset | |||
50 | private IAssetService m_GridService; | 51 | private IAssetService m_GridService; |
51 | private IAssetService m_HGService; | 52 | private IAssetService m_HGService; |
52 | 53 | ||
54 | private Scene m_aScene; | ||
55 | private string m_LocalAssetServiceURI; | ||
56 | |||
53 | private bool m_Enabled = false; | 57 | private bool m_Enabled = false; |
54 | 58 | ||
55 | public Type ReplaceableInterface | 59 | public Type ReplaceableInterface |
@@ -114,6 +118,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset | |||
114 | return; | 118 | return; |
115 | } | 119 | } |
116 | 120 | ||
121 | m_LocalAssetServiceURI = assetConfig.GetString("AssetServerURI", string.Empty); | ||
122 | if (m_LocalAssetServiceURI == string.Empty) | ||
123 | { | ||
124 | IConfig netConfig = source.Configs["Network"]; | ||
125 | m_LocalAssetServiceURI = netConfig.GetString("asset_server_url", string.Empty); | ||
126 | } | ||
127 | |||
128 | if (m_LocalAssetServiceURI != string.Empty) | ||
129 | m_LocalAssetServiceURI = m_LocalAssetServiceURI.Trim('/'); | ||
130 | |||
117 | m_Enabled = true; | 131 | m_Enabled = true; |
118 | m_log.Info("[HG ASSET CONNECTOR]: HG asset broker enabled"); | 132 | m_log.Info("[HG ASSET CONNECTOR]: HG asset broker enabled"); |
119 | } | 133 | } |
@@ -132,8 +146,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset | |||
132 | { | 146 | { |
133 | if (!m_Enabled) | 147 | if (!m_Enabled) |
134 | return; | 148 | return; |
149 | |||
150 | m_aScene = scene; | ||
135 | 151 | ||
136 | scene.RegisterModuleInterface<IAssetService>(this); | 152 | scene.RegisterModuleInterface<IAssetService>(this); |
153 | scene.RegisterModuleInterface<IHyperAssetService>(this); | ||
137 | } | 154 | } |
138 | 155 | ||
139 | public void RemoveRegion(Scene scene) | 156 | public void RemoveRegion(Scene scene) |
@@ -344,5 +361,30 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset | |||
344 | else | 361 | else |
345 | return m_GridService.Delete(id); | 362 | return m_GridService.Delete(id); |
346 | } | 363 | } |
364 | |||
365 | #region IHyperAssetService | ||
366 | |||
367 | public string GetUserAssetServer(UUID userID) | ||
368 | { | ||
369 | CachedUserInfo uinfo = m_aScene.CommsManager.UserProfileCacheService.GetUserDetails(userID); | ||
370 | if ((uinfo != null) && (uinfo.UserProfile != null)) | ||
371 | { | ||
372 | if ((uinfo.UserProfile.UserAssetURI == string.Empty) || (uinfo.UserProfile.UserAssetURI == "")) | ||
373 | return m_LocalAssetServiceURI; | ||
374 | return uinfo.UserProfile.UserAssetURI.Trim('/'); | ||
375 | } | ||
376 | else | ||
377 | { | ||
378 | // we don't know anyting about this user | ||
379 | return string.Empty; | ||
380 | } | ||
381 | } | ||
382 | |||
383 | public string GetSimAssetServer() | ||
384 | { | ||
385 | return m_LocalAssetServiceURI; | ||
386 | } | ||
387 | |||
388 | #endregion | ||
347 | } | 389 | } |
348 | } | 390 | } |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs index 148331b..1422add 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs | |||
@@ -759,6 +759,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
759 | 759 | ||
760 | } | 760 | } |
761 | 761 | ||
762 | |||
762 | protected bool IsLocalRegion(ulong handle) | 763 | protected bool IsLocalRegion(ulong handle) |
763 | { | 764 | { |
764 | return m_LocalScenes.ContainsKey(handle); | 765 | return m_LocalScenes.ContainsKey(handle); |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/BaseInventoryConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/BaseInventoryConnector.cs index bd32f3b..811569f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/BaseInventoryConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/BaseInventoryConnector.cs | |||
@@ -159,6 +159,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
159 | /// <returns>true if the item was successfully added</returns> | 159 | /// <returns>true if the item was successfully added</returns> |
160 | public bool AddItem(InventoryItemBase item) | 160 | public bool AddItem(InventoryItemBase item) |
161 | { | 161 | { |
162 | if (item == null) | ||
163 | return false; | ||
164 | |||
162 | if (item.Folder == UUID.Zero) | 165 | if (item.Folder == UUID.Zero) |
163 | { | 166 | { |
164 | InventoryFolderBase f = GetFolderForType(item.Owner, (AssetType)item.AssetType); | 167 | InventoryFolderBase f = GetFolderForType(item.Owner, (AssetType)item.AssetType); |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs index fd1a759..f073f32 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs | |||
@@ -386,7 +386,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
386 | return false; | 386 | return false; |
387 | 387 | ||
388 | if (IsLocalGridUser(item.Owner)) | 388 | if (IsLocalGridUser(item.Owner)) |
389 | { | ||
389 | return m_GridService.AddItem(item); | 390 | return m_GridService.AddItem(item); |
391 | } | ||
390 | else | 392 | else |
391 | { | 393 | { |
392 | UUID sessionID = GetSessionID(item.Owner); | 394 | UUID sessionID = GetSessionID(item.Owner); |
diff --git a/OpenSim/Region/CoreModules/World/Land/RegionCombinerModule.cs b/OpenSim/Region/CoreModules/World/Land/RegionCombinerModule.cs index 05d19a2..6499915 100644 --- a/OpenSim/Region/CoreModules/World/Land/RegionCombinerModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/RegionCombinerModule.cs | |||
@@ -343,7 +343,9 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
343 | 343 | ||
344 | lock (scene.WestBorders) | 344 | lock (scene.WestBorders) |
345 | { | 345 | { |
346 | scene.WestBorders[0].BorderLine.Z += (int) Constants.RegionSize; //auto teleport West | 346 | |
347 | |||
348 | scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - conn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West | ||
347 | 349 | ||
348 | // Trigger auto teleport to root region | 350 | // Trigger auto teleport to root region |
349 | scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; | 351 | scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; |
@@ -410,7 +412,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
410 | conn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize; | 412 | conn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize; |
411 | lock (scene.SouthBorders) | 413 | lock (scene.SouthBorders) |
412 | { | 414 | { |
413 | scene.SouthBorders[0].BorderLine.Z += (int) Constants.RegionSize; //auto teleport south | 415 | scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - conn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south |
414 | scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; | 416 | scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; |
415 | scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY; | 417 | scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY; |
416 | } | 418 | } |
@@ -481,7 +483,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
481 | 483 | ||
482 | lock (scene.SouthBorders) | 484 | lock (scene.SouthBorders) |
483 | { | 485 | { |
484 | scene.SouthBorders[0].BorderLine.Z += (int) Constants.RegionSize; //auto teleport south | 486 | scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - conn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south |
485 | scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; | 487 | scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; |
486 | scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY; | 488 | scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY; |
487 | } | 489 | } |
@@ -503,7 +505,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
503 | 505 | ||
504 | lock (scene.WestBorders) | 506 | lock (scene.WestBorders) |
505 | { | 507 | { |
506 | scene.WestBorders[0].BorderLine.Z += (int) Constants.RegionSize; //auto teleport West | 508 | scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - conn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West |
507 | scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; | 509 | scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; |
508 | scene.WestBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY; | 510 | scene.WestBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY; |
509 | } | 511 | } |
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/Interfaces/IHyperService.cs b/OpenSim/Region/Framework/Interfaces/IHyperService.cs new file mode 100644 index 0000000..51ea28a --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IHyperService.cs | |||
@@ -0,0 +1,37 @@ | |||
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 | using System; | ||
28 | using OpenMetaverse; | ||
29 | |||
30 | namespace OpenSim.Region.Framework.Interfaces | ||
31 | { | ||
32 | public interface IHyperAssetService | ||
33 | { | ||
34 | string GetUserAssetServer(UUID userID); | ||
35 | string GetSimAssetServer(); | ||
36 | } | ||
37 | } | ||
diff --git a/OpenSim/Region/Framework/Scenes/Hypergrid/HGAssetMapper.cs b/OpenSim/Region/Framework/Scenes/Hypergrid/HGAssetMapper.cs index b6fa41d..244ac3b 100644 --- a/OpenSim/Region/Framework/Scenes/Hypergrid/HGAssetMapper.cs +++ b/OpenSim/Region/Framework/Scenes/Hypergrid/HGAssetMapper.cs | |||
@@ -35,6 +35,7 @@ using OpenSim.Framework; | |||
35 | using OpenSim.Framework.Communications.Cache; | 35 | using OpenSim.Framework.Communications.Cache; |
36 | using OpenSim.Framework.Communications.Clients; | 36 | using OpenSim.Framework.Communications.Clients; |
37 | using OpenSim.Region.Framework.Scenes.Serialization; | 37 | using OpenSim.Region.Framework.Scenes.Serialization; |
38 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Services.Interfaces; | 39 | using OpenSim.Services.Interfaces; |
39 | 40 | ||
40 | //using HyperGrid.Framework; | 41 | //using HyperGrid.Framework; |
@@ -52,13 +53,13 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid | |||
52 | 53 | ||
53 | private Scene m_scene; | 54 | private Scene m_scene; |
54 | 55 | ||
55 | private IHyperlinkService m_hyper; | 56 | private IHyperAssetService m_hyper; |
56 | IHyperlinkService HyperlinkService | 57 | IHyperAssetService HyperlinkAssets |
57 | { | 58 | { |
58 | get | 59 | get |
59 | { | 60 | { |
60 | if (m_hyper == null) | 61 | if (m_hyper == null) |
61 | m_hyper = m_scene.RequestModuleInterface<IHyperlinkService>(); | 62 | m_hyper = m_scene.RequestModuleInterface<IHyperAssetService>(); |
62 | return m_hyper; | 63 | return m_hyper; |
63 | } | 64 | } |
64 | } | 65 | } |
@@ -99,7 +100,7 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid | |||
99 | 100 | ||
100 | if (asset != null) | 101 | if (asset != null) |
101 | { | 102 | { |
102 | m_log.Debug("[HGScene]: Asset made it to asset cache. " + asset.Name + " " + assetID); | 103 | m_log.DebugFormat("[HGScene]: Copied asset {0} from {1} to local asset server. ", asset.ID, url); |
103 | return asset; | 104 | return asset; |
104 | } | 105 | } |
105 | return null; | 106 | return null; |
@@ -129,6 +130,7 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid | |||
129 | } | 130 | } |
130 | 131 | ||
131 | m_scene.AssetService.Store(asset1); | 132 | m_scene.AssetService.Store(asset1); |
133 | m_log.DebugFormat("[HGScene]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url); | ||
132 | } | 134 | } |
133 | return true; | 135 | return true; |
134 | } | 136 | } |
@@ -167,34 +169,32 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid | |||
167 | 169 | ||
168 | public void Get(UUID assetID, UUID ownerID) | 170 | public void Get(UUID assetID, UUID ownerID) |
169 | { | 171 | { |
170 | if (!HyperlinkService.IsLocalUser(ownerID)) | 172 | // Get the item from the remote asset server onto the local AssetCache |
173 | // and place an entry in m_assetMap | ||
174 | |||
175 | string userAssetURL = HyperlinkAssets.GetUserAssetServer(ownerID); | ||
176 | if ((userAssetURL != string.Empty) && (userAssetURL != HyperlinkAssets.GetSimAssetServer())) | ||
171 | { | 177 | { |
172 | // Get the item from the remote asset server onto the local AssetCache | 178 | m_log.Debug("[HGScene]: Fetching object " + assetID + " from asset server " + userAssetURL); |
173 | // and place an entry in m_assetMap | 179 | AssetBase asset = FetchAsset(userAssetURL, assetID); |
174 | 180 | ||
175 | string userAssetURL = UserAssetURL(ownerID); | 181 | if (asset != null) |
176 | if (userAssetURL != null) | ||
177 | { | 182 | { |
178 | m_log.Debug("[HGScene]: Fetching object " + assetID + " to asset server " + userAssetURL); | 183 | // OK, now fetch the inside. |
179 | AssetBase asset = FetchAsset(userAssetURL, assetID); | 184 | Dictionary<UUID, int> ids = new Dictionary<UUID, int>(); |
185 | HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, userAssetURL); | ||
186 | uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids); | ||
187 | foreach (UUID uuid in ids.Keys) | ||
188 | FetchAsset(userAssetURL, uuid); | ||
189 | |||
190 | m_log.DebugFormat("[HGScene]: Successfully fetched asset {0} from asset server {1}", asset.ID, userAssetURL); | ||
180 | 191 | ||
181 | if (asset != null) | ||
182 | { | ||
183 | m_log.Debug("[HGScene]: Successfully fetched item from remote asset server " + userAssetURL); | ||
184 | |||
185 | // OK, now fetch the inside. | ||
186 | Dictionary<UUID, int> ids = new Dictionary<UUID, int>(); | ||
187 | HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, userAssetURL); | ||
188 | uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids); | ||
189 | foreach (UUID uuid in ids.Keys) | ||
190 | FetchAsset(userAssetURL, uuid); | ||
191 | } | ||
192 | else | ||
193 | m_log.Warn("[HGScene]: Could not fetch asset from remote asset server " + userAssetURL); | ||
194 | } | 192 | } |
195 | else | 193 | else |
196 | m_log.Warn("[HGScene]: Unable to locate foreign user's asset server"); | 194 | m_log.Warn("[HGScene]: Could not fetch asset from remote asset server " + userAssetURL); |
197 | } | 195 | } |
196 | else | ||
197 | m_log.Debug("[HGScene]: user's asset server is the local region's asset server"); | ||
198 | } | 198 | } |
199 | 199 | ||
200 | //public InventoryItemBase Get(InventoryItemBase item, UUID rootFolder, CachedUserInfo userInfo) | 200 | //public InventoryItemBase Get(InventoryItemBase item, UUID rootFolder, CachedUserInfo userInfo) |
@@ -225,44 +225,38 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid | |||
225 | 225 | ||
226 | public void Post(UUID assetID, UUID ownerID) | 226 | public void Post(UUID assetID, UUID ownerID) |
227 | { | 227 | { |
228 | if (!HyperlinkService.IsLocalUser(ownerID)) | ||
229 | { | ||
230 | // Post the item from the local AssetCache onto the remote asset server | 228 | // Post the item from the local AssetCache onto the remote asset server |
231 | // and place an entry in m_assetMap | 229 | // and place an entry in m_assetMap |
232 | 230 | ||
233 | string userAssetURL = UserAssetURL(ownerID); | 231 | string userAssetURL = HyperlinkAssets.GetUserAssetServer(ownerID); |
234 | if (userAssetURL != null) | 232 | if ((userAssetURL != string.Empty) && (userAssetURL != HyperlinkAssets.GetSimAssetServer())) |
233 | { | ||
234 | m_log.Debug("[HGScene]: Posting object " + assetID + " to asset server " + userAssetURL); | ||
235 | AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); | ||
236 | if (asset != null) | ||
235 | { | 237 | { |
236 | m_log.Debug("[HGScene]: Posting object " + assetID + " to asset server " + userAssetURL); | 238 | Dictionary<UUID, int> ids = new Dictionary<UUID, int>(); |
237 | AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); | 239 | HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, string.Empty); |
238 | if (asset != null) | 240 | uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids); |
241 | foreach (UUID uuid in ids.Keys) | ||
239 | { | 242 | { |
240 | Dictionary<UUID, int> ids = new Dictionary<UUID, int>(); | 243 | asset = m_scene.AssetService.Get(uuid.ToString()); |
241 | HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, string.Empty); | 244 | if (asset == null) |
242 | uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids); | 245 | m_log.DebugFormat("[HGScene]: Could not find asset {0}", uuid); |
243 | foreach (UUID uuid in ids.Keys) | 246 | else |
244 | { | ||
245 | asset = m_scene.AssetService.Get(uuid.ToString()); | ||
246 | if (asset != null) | ||
247 | m_log.DebugFormat("[HGScene]: Posting {0} {1}", asset.Type.ToString(), asset.Name); | ||
248 | else | ||
249 | m_log.DebugFormat("[HGScene]: Could not find asset {0}", uuid); | ||
250 | PostAsset(userAssetURL, asset); | 247 | PostAsset(userAssetURL, asset); |
251 | } | 248 | } |
252 | 249 | ||
253 | if (ids.Count > 0) // maybe it succeeded... | 250 | // maybe all pieces got there... |
254 | m_log.DebugFormat("[HGScene]: Successfully posted item {0} to remote asset server {1}", assetID, userAssetURL); | 251 | m_log.DebugFormat("[HGScene]: Successfully posted item {0} to asset server {1}", assetID, userAssetURL); |
255 | else | ||
256 | m_log.WarnFormat("[HGScene]: Could not post asset {0} to remote asset server {1}", assetID, userAssetURL); | ||
257 | 252 | ||
258 | } | ||
259 | else | ||
260 | m_log.Debug("[HGScene]: Something wrong with asset, it could not be found"); | ||
261 | } | 253 | } |
262 | else | 254 | else |
263 | m_log.Warn("[HGScene]: Unable to locate foreign user's asset server"); | 255 | m_log.DebugFormat("[HGScene]: Something wrong with asset {0}, it could not be found", assetID); |
264 | |||
265 | } | 256 | } |
257 | else | ||
258 | m_log.Debug("[HGScene]: user's asset server is local region's asset server"); | ||
259 | |||
266 | } | 260 | } |
267 | 261 | ||
268 | #endregion | 262 | #endregion |
diff --git a/OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.Inventory.cs index 8fe3565..6f7f34f 100644 --- a/OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.Inventory.cs | |||
@@ -32,6 +32,7 @@ using OpenMetaverse; | |||
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenSim.Framework.Communications; | 33 | using OpenSim.Framework.Communications; |
34 | using OpenSim.Framework.Communications.Cache; | 34 | using OpenSim.Framework.Communications.Cache; |
35 | using OpenSim.Region.Framework.Interfaces; | ||
35 | 36 | ||
36 | namespace OpenSim.Region.Framework.Scenes.Hypergrid | 37 | namespace OpenSim.Region.Framework.Scenes.Hypergrid |
37 | { | 38 | { |
@@ -41,6 +42,21 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid | |||
41 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
42 | 43 | ||
43 | private HGAssetMapper m_assMapper; | 44 | private HGAssetMapper m_assMapper; |
45 | public HGAssetMapper AssetMapper | ||
46 | { | ||
47 | get { return m_assMapper; } | ||
48 | } | ||
49 | |||
50 | private IHyperAssetService m_hyper; | ||
51 | private IHyperAssetService HyperAssets | ||
52 | { | ||
53 | get | ||
54 | { | ||
55 | if (m_hyper == null) | ||
56 | m_hyper = RequestModuleInterface<IHyperAssetService>(); | ||
57 | return m_hyper; | ||
58 | } | ||
59 | } | ||
44 | 60 | ||
45 | #endregion | 61 | #endregion |
46 | 62 | ||
@@ -140,6 +156,16 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid | |||
140 | 156 | ||
141 | } | 157 | } |
142 | 158 | ||
159 | protected override void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver) | ||
160 | { | ||
161 | string userAssetServer = HyperAssets.GetUserAssetServer(sender); | ||
162 | if ((userAssetServer != string.Empty) && (userAssetServer != HyperAssets.GetSimAssetServer())) | ||
163 | m_assMapper.Get(item.AssetID, sender); | ||
164 | |||
165 | userAssetServer = HyperAssets.GetUserAssetServer(receiver); | ||
166 | if ((userAssetServer != string.Empty) && (userAssetServer != HyperAssets.GetSimAssetServer())) | ||
167 | m_assMapper.Post(item.AssetID, receiver); | ||
168 | } | ||
143 | 169 | ||
144 | #endregion | 170 | #endregion |
145 | 171 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 9f7083f..890126f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | |||
@@ -408,7 +408,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
408 | public virtual InventoryItemBase GiveInventoryItem( | 408 | public virtual InventoryItemBase GiveInventoryItem( |
409 | UUID recipient, UUID senderId, UUID itemId, UUID recipientFolderId) | 409 | UUID recipient, UUID senderId, UUID itemId, UUID recipientFolderId) |
410 | { | 410 | { |
411 | Console.WriteLine("Scene.Inventory.cs: GiveInventoryItem"); | 411 | //Console.WriteLine("Scene.Inventory.cs: GiveInventoryItem"); |
412 | 412 | ||
413 | InventoryItemBase item = new InventoryItemBase(itemId, senderId); | 413 | InventoryItemBase item = new InventoryItemBase(itemId, senderId); |
414 | item = InventoryService.GetItem(item); | 414 | item = InventoryService.GetItem(item); |
@@ -472,7 +472,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
472 | itemCopy.SalePrice = item.SalePrice; | 472 | itemCopy.SalePrice = item.SalePrice; |
473 | itemCopy.SaleType = item.SaleType; | 473 | itemCopy.SaleType = item.SaleType; |
474 | 474 | ||
475 | InventoryService.AddItem(itemCopy); | 475 | if (InventoryService.AddItem(itemCopy)) |
476 | TransferInventoryAssets(itemCopy, senderId, recipient); | ||
476 | 477 | ||
477 | if (!Permissions.BypassPermissions()) | 478 | if (!Permissions.BypassPermissions()) |
478 | { | 479 | { |
@@ -494,6 +495,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
494 | 495 | ||
495 | } | 496 | } |
496 | 497 | ||
498 | protected virtual void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver) | ||
499 | { | ||
500 | } | ||
501 | |||
497 | /// <summary> | 502 | /// <summary> |
498 | /// Give an entire inventory folder from one user to another. The entire contents (including all descendent | 503 | /// Give an entire inventory folder from one user to another. The entire contents (including all descendent |
499 | /// folders) is given. | 504 | /// folders) is given. |
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 03111a6..fba9ea8 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 | ||
@@ -1780,36 +1772,87 @@ namespace OpenSim.Region.Framework.Scenes | |||
1780 | 1772 | ||
1781 | Vector3 pos = attemptedPosition; | 1773 | Vector3 pos = attemptedPosition; |
1782 | 1774 | ||
1775 | int changeX = 1; | ||
1776 | int changeY = 1; | ||
1777 | |||
1783 | if (TestBorderCross(attemptedPosition + WestCross, Cardinals.W)) | 1778 | if (TestBorderCross(attemptedPosition + WestCross, Cardinals.W)) |
1784 | { | 1779 | { |
1785 | if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) | 1780 | if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) |
1786 | { | 1781 | { |
1787 | //Border crossedBorderx = GetCrossedBorder(attemptedPosition,Cardinals.W); | 1782 | |
1788 | //Border crossedBordery = GetCrossedBorder(attemptedPosition, Cardinals.S); | 1783 | Border crossedBorderx = GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W); |
1784 | |||
1785 | if (crossedBorderx.BorderLine.Z > 0) | ||
1786 | { | ||
1787 | pos.X = ((pos.X + crossedBorderx.BorderLine.Z)); | ||
1788 | changeX = (int)(crossedBorderx.BorderLine.Z /(int) Constants.RegionSize); | ||
1789 | } | ||
1790 | else | ||
1791 | pos.X = ((pos.X + Constants.RegionSize)); | ||
1792 | |||
1793 | Border crossedBordery = GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); | ||
1789 | //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) | 1794 | //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) |
1790 | pos.X = ((pos.X + Constants.RegionSize)); | 1795 | |
1791 | pos.Y = ((pos.Y + Constants.RegionSize)); | 1796 | if (crossedBordery.BorderLine.Z > 0) |
1797 | { | ||
1798 | pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); | ||
1799 | changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); | ||
1800 | } | ||
1801 | else | ||
1802 | pos.Y = ((pos.Y + Constants.RegionSize)); | ||
1803 | |||
1804 | |||
1805 | |||
1792 | newRegionHandle | 1806 | newRegionHandle |
1793 | = Util.UIntsToLong((uint)((thisx - 1) * Constants.RegionSize), | 1807 | = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize), |
1794 | (uint)((thisy - 1) * Constants.RegionSize)); | 1808 | (uint)((thisy - changeY) * Constants.RegionSize)); |
1795 | // x - 1 | 1809 | // x - 1 |
1796 | // y - 1 | 1810 | // y - 1 |
1797 | } | 1811 | } |
1798 | else if (TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) | 1812 | else if (TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) |
1799 | { | 1813 | { |
1800 | pos.X = ((pos.X + Constants.RegionSize)); | 1814 | Border crossedBorderx = GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W); |
1801 | pos.Y = ((pos.Y - Constants.RegionSize)); | 1815 | |
1816 | if (crossedBorderx.BorderLine.Z > 0) | ||
1817 | { | ||
1818 | pos.X = ((pos.X + crossedBorderx.BorderLine.Z)); | ||
1819 | changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize); | ||
1820 | } | ||
1821 | else | ||
1822 | pos.X = ((pos.X + Constants.RegionSize)); | ||
1823 | |||
1824 | |||
1825 | Border crossedBordery = GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); | ||
1826 | //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) | ||
1827 | |||
1828 | if (crossedBordery.BorderLine.Z > 0) | ||
1829 | { | ||
1830 | pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); | ||
1831 | changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); | ||
1832 | } | ||
1833 | else | ||
1834 | pos.Y = ((pos.Y + Constants.RegionSize)); | ||
1835 | |||
1802 | newRegionHandle | 1836 | newRegionHandle |
1803 | = Util.UIntsToLong((uint)((thisx - 1) * Constants.RegionSize), | 1837 | = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize), |
1804 | (uint)((thisy + 1) * Constants.RegionSize)); | 1838 | (uint)((thisy + changeY) * Constants.RegionSize)); |
1805 | // x - 1 | 1839 | // x - 1 |
1806 | // y + 1 | 1840 | // y + 1 |
1807 | } | 1841 | } |
1808 | else | 1842 | else |
1809 | { | 1843 | { |
1810 | pos.X = ((pos.X + Constants.RegionSize)); | 1844 | Border crossedBorderx = GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W); |
1845 | |||
1846 | if (crossedBorderx.BorderLine.Z > 0) | ||
1847 | { | ||
1848 | pos.X = ((pos.X + crossedBorderx.BorderLine.Z)); | ||
1849 | changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize); | ||
1850 | } | ||
1851 | else | ||
1852 | pos.X = ((pos.X + Constants.RegionSize)); | ||
1853 | |||
1811 | newRegionHandle | 1854 | newRegionHandle |
1812 | = Util.UIntsToLong((uint) ((thisx - 1)*Constants.RegionSize), | 1855 | = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize), |
1813 | (uint) (thisy*Constants.RegionSize)); | 1856 | (uint) (thisy*Constants.RegionSize)); |
1814 | // x - 1 | 1857 | // x - 1 |
1815 | } | 1858 | } |
@@ -1818,11 +1861,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
1818 | { | 1861 | { |
1819 | if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) | 1862 | if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) |
1820 | { | 1863 | { |
1864 | |||
1821 | pos.X = ((pos.X - Constants.RegionSize)); | 1865 | pos.X = ((pos.X - Constants.RegionSize)); |
1822 | pos.Y = ((pos.Y + Constants.RegionSize)); | 1866 | Border crossedBordery = GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); |
1867 | //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) | ||
1868 | |||
1869 | if (crossedBordery.BorderLine.Z > 0) | ||
1870 | { | ||
1871 | pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); | ||
1872 | changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); | ||
1873 | } | ||
1874 | else | ||
1875 | pos.Y = ((pos.Y + Constants.RegionSize)); | ||
1876 | |||
1877 | |||
1823 | newRegionHandle | 1878 | newRegionHandle |
1824 | = Util.UIntsToLong((uint)((thisx + 1) * Constants.RegionSize), | 1879 | = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), |
1825 | (uint)((thisy - 1) * Constants.RegionSize)); | 1880 | (uint)((thisy - changeY) * Constants.RegionSize)); |
1826 | // x + 1 | 1881 | // x + 1 |
1827 | // y - 1 | 1882 | // y - 1 |
1828 | } | 1883 | } |
@@ -1831,8 +1886,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1831 | pos.X = ((pos.X - Constants.RegionSize)); | 1886 | pos.X = ((pos.X - Constants.RegionSize)); |
1832 | pos.Y = ((pos.Y - Constants.RegionSize)); | 1887 | pos.Y = ((pos.Y - Constants.RegionSize)); |
1833 | newRegionHandle | 1888 | newRegionHandle |
1834 | = Util.UIntsToLong((uint)((thisx + 1) * Constants.RegionSize), | 1889 | = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), |
1835 | (uint)((thisy + 1) * Constants.RegionSize)); | 1890 | (uint)((thisy + changeY) * Constants.RegionSize)); |
1836 | // x + 1 | 1891 | // x + 1 |
1837 | // y + 1 | 1892 | // y + 1 |
1838 | } | 1893 | } |
@@ -1840,16 +1895,26 @@ namespace OpenSim.Region.Framework.Scenes | |||
1840 | { | 1895 | { |
1841 | pos.X = ((pos.X - Constants.RegionSize)); | 1896 | pos.X = ((pos.X - Constants.RegionSize)); |
1842 | newRegionHandle | 1897 | newRegionHandle |
1843 | = Util.UIntsToLong((uint) ((thisx + 1)*Constants.RegionSize), | 1898 | = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), |
1844 | (uint) (thisy*Constants.RegionSize)); | 1899 | (uint) (thisy*Constants.RegionSize)); |
1845 | // x + 1 | 1900 | // x + 1 |
1846 | } | 1901 | } |
1847 | } | 1902 | } |
1848 | else if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) | 1903 | else if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) |
1849 | { | 1904 | { |
1850 | pos.Y = ((pos.Y + Constants.RegionSize)); | 1905 | Border crossedBordery = GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); |
1906 | //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) | ||
1907 | |||
1908 | if (crossedBordery.BorderLine.Z > 0) | ||
1909 | { | ||
1910 | pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); | ||
1911 | changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); | ||
1912 | } | ||
1913 | else | ||
1914 | pos.Y = ((pos.Y + Constants.RegionSize)); | ||
1915 | |||
1851 | newRegionHandle | 1916 | newRegionHandle |
1852 | = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - 1) * Constants.RegionSize)); | 1917 | = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - changeY) * Constants.RegionSize)); |
1853 | // y - 1 | 1918 | // y - 1 |
1854 | } | 1919 | } |
1855 | else if (TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) | 1920 | else if (TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) |
@@ -1857,7 +1922,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1857 | 1922 | ||
1858 | pos.Y = ((pos.Y - Constants.RegionSize)); | 1923 | pos.Y = ((pos.Y - Constants.RegionSize)); |
1859 | newRegionHandle | 1924 | newRegionHandle |
1860 | = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + 1) * Constants.RegionSize)); | 1925 | = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + changeY) * Constants.RegionSize)); |
1861 | // y + 1 | 1926 | // y + 1 |
1862 | } | 1927 | } |
1863 | 1928 | ||
@@ -2363,6 +2428,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2363 | /// <param name="client"></param> | 2428 | /// <param name="client"></param> |
2364 | public override void AddNewClient(IClientAPI client) | 2429 | public override void AddNewClient(IClientAPI client) |
2365 | { | 2430 | { |
2431 | ClientManager.Add(client); | ||
2432 | |||
2366 | CheckHeartbeat(); | 2433 | CheckHeartbeat(); |
2367 | SubscribeToClientEvents(client); | 2434 | SubscribeToClientEvents(client); |
2368 | ScenePresence presence; | 2435 | ScenePresence presence; |
@@ -2572,6 +2639,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2572 | public virtual void SubscribeToClientNetworkEvents(IClientAPI client) | 2639 | public virtual void SubscribeToClientNetworkEvents(IClientAPI client) |
2573 | { | 2640 | { |
2574 | client.OnNetworkStatsUpdate += StatsReporter.AddPacketsStats; | 2641 | client.OnNetworkStatsUpdate += StatsReporter.AddPacketsStats; |
2642 | client.OnViewerEffect += ProcessViewerEffect; | ||
2575 | } | 2643 | } |
2576 | 2644 | ||
2577 | protected virtual void UnsubscribeToClientEvents(IClientAPI client) | 2645 | protected virtual void UnsubscribeToClientEvents(IClientAPI client) |
@@ -2726,11 +2794,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2726 | public virtual void UnSubscribeToClientNetworkEvents(IClientAPI client) | 2794 | public virtual void UnSubscribeToClientNetworkEvents(IClientAPI client) |
2727 | { | 2795 | { |
2728 | client.OnNetworkStatsUpdate -= StatsReporter.AddPacketsStats; | 2796 | client.OnNetworkStatsUpdate -= StatsReporter.AddPacketsStats; |
2797 | client.OnViewerEffect -= ProcessViewerEffect; | ||
2729 | } | 2798 | } |
2730 | 2799 | ||
2731 | |||
2732 | |||
2733 | |||
2734 | /// <summary> | 2800 | /// <summary> |
2735 | /// Teleport an avatar to their home region | 2801 | /// Teleport an avatar to their home region |
2736 | /// </summary> | 2802 | /// </summary> |
@@ -3003,7 +3069,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
3003 | agentTransactions.RemoveAgentAssetTransactions(agentID); | 3069 | agentTransactions.RemoveAgentAssetTransactions(agentID); |
3004 | } | 3070 | } |
3005 | 3071 | ||
3072 | // Remove the avatar from the scene | ||
3006 | m_sceneGraph.RemoveScenePresence(agentID); | 3073 | m_sceneGraph.RemoveScenePresence(agentID); |
3074 | ClientManager.Remove(agentID); | ||
3007 | 3075 | ||
3008 | try | 3076 | try |
3009 | { | 3077 | { |
@@ -3053,16 +3121,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3053 | } | 3121 | } |
3054 | 3122 | ||
3055 | /// <summary> | 3123 | /// <summary> |
3056 | /// Closes all endpoints with the circuitcode provided. | ||
3057 | /// </summary> | ||
3058 | /// <param name="circuitcode">Circuit Code of the endpoint to close</param> | ||
3059 | public override void CloseAllAgents(uint circuitcode) | ||
3060 | { | ||
3061 | // Called by ClientView to kill all circuit codes | ||
3062 | ClientManager.CloseAllAgents(circuitcode); | ||
3063 | } | ||
3064 | |||
3065 | /// <summary> | ||
3066 | /// 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. |
3067 | /// </summary> | 3125 | /// </summary> |
3068 | public void NotifyMyCoarseLocationChange() | 3126 | public void NotifyMyCoarseLocationChange() |
@@ -3383,7 +3441,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3383 | loggingOffUser.ControllingClient.Kick(message); | 3441 | loggingOffUser.ControllingClient.Kick(message); |
3384 | // Give them a second to receive the message! | 3442 | // Give them a second to receive the message! |
3385 | Thread.Sleep(1000); | 3443 | Thread.Sleep(1000); |
3386 | loggingOffUser.ControllingClient.Close(true); | 3444 | loggingOffUser.ControllingClient.Close(); |
3387 | } | 3445 | } |
3388 | else | 3446 | else |
3389 | { | 3447 | { |
@@ -3554,7 +3612,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3554 | presence.ControllingClient.SendShutdownConnectionNotice(); | 3612 | presence.ControllingClient.SendShutdownConnectionNotice(); |
3555 | } | 3613 | } |
3556 | 3614 | ||
3557 | presence.ControllingClient.Close(true); | 3615 | presence.ControllingClient.Close(); |
3558 | return true; | 3616 | return true; |
3559 | } | 3617 | } |
3560 | 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 cda0bfc..ba5119f 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 be8a6c9..b8bd9b4 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -1241,6 +1241,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1241 | { | 1241 | { |
1242 | lock (m_targets) | 1242 | lock (m_targets) |
1243 | m_targets.Clear(); | 1243 | m_targets.Clear(); |
1244 | m_scene.RemoveGroupTarget(this); | ||
1244 | } | 1245 | } |
1245 | 1246 | ||
1246 | ScheduleGroupForFullUpdate(); | 1247 | ScheduleGroupForFullUpdate(); |
@@ -1871,12 +1872,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1871 | m_rootPart.UpdateFlag = 1; | 1872 | m_rootPart.UpdateFlag = 1; |
1872 | lastPhysGroupPos = AbsolutePosition; | 1873 | lastPhysGroupPos = AbsolutePosition; |
1873 | } | 1874 | } |
1874 | //foreach (SceneObjectPart part in m_parts.Values) | ||
1875 | //{ | ||
1876 | //if (part.UpdateFlag == 0) part.UpdateFlag = 1; | ||
1877 | //} | ||
1878 | |||
1879 | checkAtTargets(); | ||
1880 | 1875 | ||
1881 | if (UsePhysics && ((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1) | 1876 | if (UsePhysics && ((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1) |
1882 | || (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1) | 1877 | || (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1) |
@@ -3126,6 +3121,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3126 | { | 3121 | { |
3127 | m_targets.Add(handle, waypoint); | 3122 | m_targets.Add(handle, waypoint); |
3128 | } | 3123 | } |
3124 | m_scene.AddGroupTarget(this); | ||
3129 | return (int)handle; | 3125 | return (int)handle; |
3130 | } | 3126 | } |
3131 | 3127 | ||
@@ -3133,12 +3129,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
3133 | { | 3129 | { |
3134 | lock (m_targets) | 3130 | lock (m_targets) |
3135 | { | 3131 | { |
3136 | if (m_targets.ContainsKey((uint)handle)) | 3132 | m_targets.Remove((uint)handle); |
3137 | m_targets.Remove((uint)handle); | 3133 | if (m_targets.Count == 0) |
3134 | m_scene.RemoveGroupTarget(this); | ||
3138 | } | 3135 | } |
3139 | } | 3136 | } |
3140 | 3137 | ||
3141 | private void checkAtTargets() | 3138 | public void checkAtTargets() |
3142 | { | 3139 | { |
3143 | if (m_scriptListens_atTarget || m_scriptListens_notAtTarget) | 3140 | if (m_scriptListens_atTarget || m_scriptListens_notAtTarget) |
3144 | { | 3141 | { |
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/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index b79c356..7c176bb 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | |||
@@ -863,7 +863,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
863 | World.Entities.TryGetValue(objecUUID, out SensedObject); | 863 | World.Entities.TryGetValue(objecUUID, out SensedObject); |
864 | 864 | ||
865 | if (SensedObject == null) | 865 | if (SensedObject == null) |
866 | { | ||
867 | IGroupsModule groups = World.RequestModuleInterface<IGroupsModule>(); | ||
868 | if (groups != null) | ||
869 | { | ||
870 | GroupRecord gr = groups.GetGroupRecord(objecUUID); | ||
871 | if (gr != null) | ||
872 | return gr.GroupName; | ||
873 | } | ||
866 | return String.Empty; | 874 | return String.Empty; |
875 | } | ||
876 | |||
867 | return SensedObject.Name; | 877 | return SensedObject.Name; |
868 | } | 878 | } |
869 | 879 | ||
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/Services/Connectors/Asset/AssetServiceConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs index 6f7c90f..ecda85a 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs | |||
@@ -298,7 +298,7 @@ namespace OpenSim.Services.Connectors | |||
298 | return; | 298 | return; |
299 | } | 299 | } |
300 | 300 | ||
301 | AssetBase asset = asset = m_Cache.Get(assetID.ToString()); | 301 | AssetBase asset = m_Cache.Get(assetID.ToString()); |
302 | 302 | ||
303 | if (asset == null) | 303 | if (asset == null) |
304 | { | 304 | { |
diff --git a/OpenSim/Services/Connectors/Inventory/HGInventoryServiceConnector.cs b/OpenSim/Services/Connectors/Inventory/HGInventoryServiceConnector.cs index 1004fb9..9878855 100644 --- a/OpenSim/Services/Connectors/Inventory/HGInventoryServiceConnector.cs +++ b/OpenSim/Services/Connectors/Inventory/HGInventoryServiceConnector.cs | |||
@@ -299,6 +299,7 @@ namespace OpenSim.Services.Connectors.Inventory | |||
299 | 299 | ||
300 | if (StringToUrlAndUserID(id, out url, out userID)) | 300 | if (StringToUrlAndUserID(id, out url, out userID)) |
301 | { | 301 | { |
302 | //m_log.DebugFormat("[HGInventory CONNECTOR]: calling {0}", url); | ||
302 | ISessionAuthInventoryService connector = GetConnector(url); | 303 | ISessionAuthInventoryService connector = GetConnector(url); |
303 | return connector.QueryItem(userID, item, sessionID); | 304 | return connector.QueryItem(userID, item, sessionID); |
304 | } | 305 | } |
diff --git a/OpenSim/Services/Connectors/User/UserServiceConnector.cs b/OpenSim/Services/Connectors/User/UserServiceConnector.cs index d418938..683990f 100644 --- a/OpenSim/Services/Connectors/User/UserServiceConnector.cs +++ b/OpenSim/Services/Connectors/User/UserServiceConnector.cs | |||
@@ -45,7 +45,7 @@ namespace OpenSim.Services.Connectors | |||
45 | LogManager.GetLogger( | 45 | LogManager.GetLogger( |
46 | MethodBase.GetCurrentMethod().DeclaringType); | 46 | MethodBase.GetCurrentMethod().DeclaringType); |
47 | 47 | ||
48 | private string m_ServerURI = String.Empty; | 48 | // private string m_ServerURI = String.Empty; |
49 | 49 | ||
50 | public UserServicesConnector() | 50 | public UserServicesConnector() |
51 | { | 51 | { |
@@ -53,7 +53,7 @@ namespace OpenSim.Services.Connectors | |||
53 | 53 | ||
54 | public UserServicesConnector(string serverURI) | 54 | public UserServicesConnector(string serverURI) |
55 | { | 55 | { |
56 | m_ServerURI = serverURI.TrimEnd('/'); | 56 | // m_ServerURI = serverURI.TrimEnd('/'); |
57 | } | 57 | } |
58 | 58 | ||
59 | public UserServicesConnector(IConfigSource source) | 59 | public UserServicesConnector(IConfigSource source) |
@@ -78,7 +78,7 @@ namespace OpenSim.Services.Connectors | |||
78 | m_log.Error("[USER CONNECTOR]: No Server URI named in section UserService"); | 78 | m_log.Error("[USER CONNECTOR]: No Server URI named in section UserService"); |
79 | throw new Exception("User connector init error"); | 79 | throw new Exception("User connector init error"); |
80 | } | 80 | } |
81 | m_ServerURI = serviceURI; | 81 | //m_ServerURI = serviceURI; |
82 | } | 82 | } |
83 | 83 | ||
84 | public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) | 84 | public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) |
diff --git a/OpenSim/Services/Interfaces/IGridService.cs b/OpenSim/Services/Interfaces/IGridService.cs index 14560b1..e69e4cd 100644 --- a/OpenSim/Services/Interfaces/IGridService.cs +++ b/OpenSim/Services/Interfaces/IGridService.cs | |||
@@ -200,6 +200,12 @@ namespace OpenSim.Services.Interfaces | |||
200 | Maturity = ConvertFrom.RegionSettings.Maturity; | 200 | Maturity = ConvertFrom.RegionSettings.Maturity; |
201 | RegionSecret = ConvertFrom.regionSecret; | 201 | RegionSecret = ConvertFrom.regionSecret; |
202 | EstateOwner = ConvertFrom.EstateSettings.EstateOwner; | 202 | EstateOwner = ConvertFrom.EstateSettings.EstateOwner; |
203 | if (EstateOwner == UUID.Zero) | ||
204 | { | ||
205 | EstateOwner = ConvertFrom.MasterAvatarAssignedUUID; | ||
206 | ConvertFrom.EstateSettings.EstateOwner = EstateOwner; | ||
207 | ConvertFrom.EstateSettings.Save(); | ||
208 | } | ||
203 | } | 209 | } |
204 | 210 | ||
205 | public GridRegion(GridRegion ConvertFrom) | 211 | public GridRegion(GridRegion ConvertFrom) |
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 | } |
diff --git a/ThirdPartyLicenses/BclExtras.txt b/ThirdPartyLicenses/BclExtras.txt new file mode 100644 index 0000000..a8a0292 --- /dev/null +++ b/ThirdPartyLicenses/BclExtras.txt | |||
@@ -0,0 +1,60 @@ | |||
1 | MICROSOFT PUBLIC LICENSE (Ms-PL) | ||
2 | |||
3 | This license governs use of the accompanying software. If you use the software, | ||
4 | you accept this license. If you do not accept the license, do not use the | ||
5 | software. | ||
6 | |||
7 | 1. Definitions | ||
8 | |||
9 | The terms "reproduce," "reproduction," "derivative works," and "distribution" | ||
10 | have the same meaning here as under U.S. copyright law. | ||
11 | |||
12 | A "contribution" is the original software, or any additions or changes to the | ||
13 | software. | ||
14 | |||
15 | A "contributor" is any person that distributes its contribution under this | ||
16 | license. | ||
17 | |||
18 | "Licensed patents" are a contributor's patent claims that read directly on its | ||
19 | contribution. | ||
20 | |||
21 | 2. Grant of Rights | ||
22 | |||
23 | (A) Copyright Grant- Subject to the terms of this license, including the license | ||
24 | conditions and limitations in section 3, each contributor grants you a | ||
25 | non-exclusive, worldwide, royalty-free copyright license to reproduce its | ||
26 | contribution, prepare derivative works of its contribution, and distribute its | ||
27 | contribution or any derivative works that you create. | ||
28 | |||
29 | (B) Patent Grant- Subject to the terms of this license, including the license | ||
30 | conditions and limitations in section 3, each contributor grants you a | ||
31 | non-exclusive, worldwide, royalty-free license under its licensed patents to | ||
32 | make, have made, use, sell, offer for sale, import, and/or otherwise dispose of | ||
33 | its contribution in the software or derivative works of the contribution in the | ||
34 | software. | ||
35 | |||
36 | 3. Conditions and Limitations | ||
37 | |||
38 | (A) No Trademark License- This license does not grant you rights to use any | ||
39 | contributors' name, logo, or trademarks. | ||
40 | |||
41 | (B) If you bring a patent claim against any contributor over patents that you | ||
42 | claim are infringed by the software, your patent license from such contributor | ||
43 | to the software ends automatically. | ||
44 | |||
45 | (C) If you distribute any portion of the software, you must retain all | ||
46 | copyright, patent, trademark, and attribution notices that are present in the | ||
47 | software. | ||
48 | |||
49 | (D) If you distribute any portion of the software in source code form, you may | ||
50 | do so only under this license by including a complete copy of this license with | ||
51 | your distribution. If you distribute any portion of the software in compiled or | ||
52 | object code form, you may only do so under a license that complies with this | ||
53 | license. | ||
54 | |||
55 | (E) The software is licensed "as-is." You bear the risk of using it. The | ||
56 | contributors give no express warranties, guarantees or conditions. You may have | ||
57 | additional consumer rights under your local laws which this license cannot | ||
58 | change. To the extent permitted under your local laws, the contributors exclude | ||
59 | the implied warranties of merchantability, fitness for a particular purpose and | ||
60 | non-infringement. | ||
diff --git a/ThirdPartyLicenses/CSJ2K.txt b/ThirdPartyLicenses/CSJ2K.txt new file mode 100644 index 0000000..3032548 --- /dev/null +++ b/ThirdPartyLicenses/CSJ2K.txt | |||
@@ -0,0 +1,28 @@ | |||
1 | Copyright (c) 1999/2000 JJ2000 Partners. | ||
2 | |||
3 | This software module was originally developed by Raphaël Grosbois and | ||
4 | Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel | ||
5 | Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David | ||
6 | Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research | ||
7 | Centre France S.A) in the course of development of the JPEG2000 | ||
8 | standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This | ||
9 | software module is an implementation of a part of the JPEG 2000 | ||
10 | Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio | ||
11 | Systems AB and Canon Research Centre France S.A (collectively JJ2000 | ||
12 | Partners) agree not to assert against ISO/IEC and users of the JPEG | ||
13 | 2000 Standard (Users) any of their rights under the copyright, not | ||
14 | including other intellectual property rights, for this software module | ||
15 | with respect to the usage by ISO/IEC and Users of this software module | ||
16 | or modifications thereof for use in hardware or software products | ||
17 | claiming conformance to the JPEG 2000 Standard. Those intending to use | ||
18 | this software module in hardware or software products are advised that | ||
19 | their use may infringe existing patents. The original developers of | ||
20 | this software module, JJ2000 Partners and ISO/IEC assume no liability | ||
21 | for use of this software module or modifications thereof. No license | ||
22 | or right to this software module is granted for non JPEG 2000 Standard | ||
23 | conforming products. JJ2000 Partners have full right to use this | ||
24 | software module for his/her own purpose, assign or donate this | ||
25 | software module to any third party and to inhibit third parties from | ||
26 | using this software module for non JPEG 2000 Standard conforming | ||
27 | products. This copyright notice must be included in all copies or | ||
28 | derivative works of this software module. | ||
diff --git a/bin/BclExtras.dll b/bin/BclExtras.dll new file mode 100644 index 0000000..505cf01 --- /dev/null +++ b/bin/BclExtras.dll | |||
Binary files differ | |||
diff --git a/bin/OpenSim.Region.ClientStack.LindenUDP.Tests.dll.config b/bin/OpenSim.Region.ClientStack.LindenUDP.Tests.dll.config deleted file mode 100644 index a3f681d..0000000 --- a/bin/OpenSim.Region.ClientStack.LindenUDP.Tests.dll.config +++ /dev/null | |||
@@ -1,33 +0,0 @@ | |||
1 | <?xml version="1.0" encoding="utf-8" ?> | ||
2 | <configuration> | ||
3 | <configSections> | ||
4 | <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /> | ||
5 | </configSections> | ||
6 | <runtime> | ||
7 | <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> | ||
8 | <dependentAssembly> | ||
9 | <assemblyIdentity name="nunit.framework" publicKeyToken="96d09a1eb7f44a77" culture="Neutral" /> | ||
10 | <bindingRedirect oldVersion="2.0.6.0" newVersion="2.4.6.0" /> | ||
11 | <bindingRedirect oldVersion="2.1.4.0" newVersion="2.4.6.0" /> | ||
12 | <bindingRedirect oldVersion="2.2.8.0" newVersion="2.4.6.0" /> | ||
13 | </dependentAssembly> | ||
14 | </assemblyBinding> | ||
15 | </runtime> | ||
16 | <log4net> | ||
17 | <!-- A1 is set to be a ConsoleAppender --> | ||
18 | <appender name="A1" type="log4net.Appender.ConsoleAppender"> | ||
19 | |||
20 | <!-- A1 uses PatternLayout --> | ||
21 | <layout type="log4net.Layout.PatternLayout"> | ||
22 | <!-- Print the date in ISO 8601 format --> | ||
23 | <conversionPattern value="%date [%thread] %-5level %logger %ndc - %message%newline" /> | ||
24 | </layout> | ||
25 | </appender> | ||
26 | |||
27 | <!-- Set root logger level to DEBUG and its only appender to A1 --> | ||
28 | <root> | ||
29 | <level value="DEBUG" /> | ||
30 | <appender-ref ref="A1" /> | ||
31 | </root> | ||
32 | </log4net> | ||
33 | </configuration> | ||
diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 5cb51b2..002745d 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example | |||
@@ -341,26 +341,13 @@ | |||
341 | 341 | ||
342 | 342 | ||
343 | [ClientStack.LindenUDP] | 343 | [ClientStack.LindenUDP] |
344 | ; This is the multiplier applied to all client throttles for outgoing UDP network data | 344 | ; Set this to true to process incoming packets asynchronously. Networking is |
345 | ; If it is set to 1, then we obey the throttle settings as given to us by the client. If it is set to 3, for example, then we | 345 | ; already separated from packet handling with a queue, so this will only |
346 | ; multiply that setting by 3 (e.g. if the client gives us a setting of 250 kilobits per second then we | 346 | ; affect whether networking internals such as packet decoding and |
347 | ; will actually push down data at a maximum rate of 750 kilobits per second). | 347 | ; acknowledgement accounting are done synchronously or asynchronously |
348 | ; | 348 | async_packet_handling = false |
349 | ; In principle, setting a multiplier greater than 1 will allow data to be pushed down to a client much faster | ||
350 | ; than its UI allows the setting to go. This may be okay in some situations, such as standalone OpenSim | ||
351 | ; applications on a LAN. However, the greater the multipler, the higher the risk of packet drop, resulting | ||
352 | ; in symptoms such as missing terrain or objects. A much better solution is to change the client UI to allow | ||
353 | ; higher network bandwidth settings directly, though this isn't always possible. | ||
354 | ; | ||
355 | ; Currently this setting is 2 by default because we currently send much more texture data than is strictly | ||
356 | ; necessary. A setting of 1 could result in slow texture transfer. This will be fixed when the transfer | ||
357 | ; of textures at different levels of quality is improved. | ||
358 | ; | ||
359 | ; Pre r7113, this setting was not exposed but was effectively 8. You may want to try this if you encounter | ||
360 | ; unexpected difficulties | ||
361 | client_throttle_multiplier = 2; | ||
362 | 349 | ||
363 | ; the client socket receive buffer size determines how many | 350 | ; The client socket receive buffer size determines how many |
364 | ; incoming requests we can process; the default on .NET is 8192 | 351 | ; incoming requests we can process; the default on .NET is 8192 |
365 | ; which is about 2 4k-sized UDP datagrams. On mono this is | 352 | ; which is about 2 4k-sized UDP datagrams. On mono this is |
366 | ; whatever the underlying operating system has as default; for | 353 | ; whatever the underlying operating system has as default; for |
@@ -374,12 +361,42 @@ | |||
374 | ; by the system's settings for the maximum client receive buffer | 361 | ; by the system's settings for the maximum client receive buffer |
375 | ; size (on linux systems you can set that with "sysctl -w | 362 | ; size (on linux systems you can set that with "sysctl -w |
376 | ; net.core.rmem_max=X") | 363 | ; net.core.rmem_max=X") |
377 | ; | 364 | ;client_socket_rcvbuf_size = 8388608 |
378 | ; client_socket_rcvbuf_size = 8388608 | 365 | |
379 | 366 | ; Maximum outbound bytes per second for a single scene. This can be used to | |
380 | ; Maximum bits per second to send to any single client. This will override the user's viewer preference settings. | 367 | ; throttle total outbound UDP traffic for a simulator. The default value is |
381 | 368 | ; 0, meaning no throttling at the scene level. The example given here is | |
382 | ; client_throttle_max_bps = 1500000 | 369 | ; 20 megabits |
370 | ;scene_throttle_max_bps = 2621440 | ||
371 | |||
372 | ; Maximum bits per second to send to any single client. This will override | ||
373 | ; the user's viewer preference settings. The default value is 0, meaning no | ||
374 | ; aggregate throttling on clients (only per-category throttling). The | ||
375 | ; example given here is 1.5 megabits | ||
376 | ;client_throttle_max_bps = 196608 | ||
377 | |||
378 | ; Per-client bytes per second rates for the various throttle categories. | ||
379 | ; These are default values that will be overriden by clients | ||
380 | ;resend_default = 12500 | ||
381 | ;land_default = 500 | ||
382 | ;wind_default = 500 | ||
383 | ;cloud_default = 50 | ||
384 | ;task_default = 500 | ||
385 | ;texture_default = 500 | ||
386 | ;asset_default = 500 | ||
387 | ;state_default = 500 | ||
388 | |||
389 | ; Per-client maximum burst rates in bytes per second for the various | ||
390 | ; throttle categories. These are default values that will be overriden by | ||
391 | ; clients | ||
392 | ;resend_limit = 18750 | ||
393 | ;land_limit = 29750 | ||
394 | ;wind_limit = 18750 | ||
395 | ;cloud_limit = 18750 | ||
396 | ;task_limit = 18750 | ||
397 | ;texture_limit = 55750 | ||
398 | ;asset_limit = 27500 | ||
399 | ;state_limit = 37000 | ||
383 | 400 | ||
384 | [Chat] | 401 | [Chat] |
385 | ; Controls whether the chat module is enabled. Default is true. | 402 | ; Controls whether the chat module is enabled. Default is true. |
@@ -1381,6 +1398,10 @@ | |||
1381 | [AssetService] | 1398 | [AssetService] |
1382 | DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll" | 1399 | DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll" |
1383 | AssetLoaderArgs = "assets/AssetSets.xml" | 1400 | AssetLoaderArgs = "assets/AssetSets.xml" |
1401 | |||
1402 | ; Disable this to prevent the default asset set from being inserted into the | ||
1403 | ; asset store each time the region starts | ||
1404 | AssetLoaderEnabled = true | ||
1384 | 1405 | ||
1385 | [GridService] | 1406 | [GridService] |
1386 | ;; default standalone, overridable in StandaloneCommon.ini | 1407 | ;; default standalone, overridable in StandaloneCommon.ini |
diff --git a/bin/config-include/FlotsamCache.ini.example b/bin/config-include/FlotsamCache.ini.example index abb3b9a..b50d7ec 100644 --- a/bin/config-include/FlotsamCache.ini.example +++ b/bin/config-include/FlotsamCache.ini.example | |||
@@ -50,3 +50,10 @@ | |||
50 | 50 | ||
51 | ; Warning level for cache directory size | 51 | ; Warning level for cache directory size |
52 | ;CacheWarnAt = 30000 | 52 | ;CacheWarnAt = 30000 |
53 | |||
54 | ; Perform a deep scan of all assets within all regions, looking for all assets | ||
55 | ; present or referenced. Mark all assets found that are already present in the | ||
56 | ; cache, and request all assets that are found that are not already cached (this | ||
57 | ; will cause those assets to be cached) | ||
58 | ; | ||
59 | ; DeepScanBeforePurge = false | ||
diff --git a/prebuild.xml b/prebuild.xml index bba54f3..1a491a7 100644 --- a/prebuild.xml +++ b/prebuild.xml | |||
@@ -135,6 +135,7 @@ | |||
135 | <Reference name="System.Xml"/> | 135 | <Reference name="System.Xml"/> |
136 | <Reference name="System.Data"/> | 136 | <Reference name="System.Data"/> |
137 | <Reference name="System.Drawing"/> | 137 | <Reference name="System.Drawing"/> |
138 | <Reference name="BclExtras.dll"/> | ||
138 | <Reference name="OpenMetaverseTypes.dll"/> | 139 | <Reference name="OpenMetaverseTypes.dll"/> |
139 | <Reference name="OpenMetaverse.dll"/> | 140 | <Reference name="OpenMetaverse.dll"/> |
140 | <Reference name="OpenMetaverse.StructuredData.dll"/> | 141 | <Reference name="OpenMetaverse.StructuredData.dll"/> |
@@ -1767,6 +1768,7 @@ | |||
1767 | <Reference name="OpenSim.Region.Communications.Local"/> | 1768 | <Reference name="OpenSim.Region.Communications.Local"/> |
1768 | <Reference name="OpenSim.Region.Physics.Manager"/> | 1769 | <Reference name="OpenSim.Region.Physics.Manager"/> |
1769 | <Reference name="OpenSim.Services.Interfaces"/> | 1770 | <Reference name="OpenSim.Services.Interfaces"/> |
1771 | <Reference name="BclExtras.dll"/> | ||
1770 | <Reference name="XMLRPC.dll"/> | 1772 | <Reference name="XMLRPC.dll"/> |
1771 | <Reference name="Nini.dll" /> | 1773 | <Reference name="Nini.dll" /> |
1772 | <Reference name="log4net.dll"/> | 1774 | <Reference name="log4net.dll"/> |
@@ -3495,7 +3497,6 @@ | |||
3495 | <Reference name="OpenSim.Tests.Common"/> | 3497 | <Reference name="OpenSim.Tests.Common"/> |
3496 | <Reference name="OpenSim.Framework"/> | 3498 | <Reference name="OpenSim.Framework"/> |
3497 | <Reference name="OpenSim.Framework.Serialization"/> | 3499 | <Reference name="OpenSim.Framework.Serialization"/> |
3498 | <Reference name="OpenSim.Framework.Serialization.External"/> | ||
3499 | <Reference name="log4net.dll"/> | 3500 | <Reference name="log4net.dll"/> |
3500 | <Reference name="nunit.framework.dll" /> | 3501 | <Reference name="nunit.framework.dll" /> |
3501 | 3502 | ||