aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Framework/Pool.cs76
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs54
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs31
3 files changed, 131 insertions, 30 deletions
diff --git a/OpenSim/Framework/Pool.cs b/OpenSim/Framework/Pool.cs
new file mode 100644
index 0000000..1ca06c3
--- /dev/null
+++ b/OpenSim/Framework/Pool.cs
@@ -0,0 +1,76 @@
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
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Framework
32{
33 /// <summary>
34 /// Naive pool implementation.
35 /// </summary>
36 /// <remarks>
37 /// Currently assumes that objects are in a useable state when returned.
38 /// </remarks>
39 public class Pool<T>
40 {
41 private Stack<T> m_pool;
42
43 private int m_maxPoolSize;
44
45 private Func<T> m_createFunction;
46
47 public Pool(Func<T> createFunction, int maxSize)
48 {
49 m_maxPoolSize = maxSize;
50 m_createFunction = createFunction;
51 m_pool = new Stack<T>(m_maxPoolSize);
52 }
53
54 public T GetObject()
55 {
56 lock (m_pool)
57 {
58 if (m_pool.Count > 0)
59 return m_pool.Pop();
60 else
61 return m_createFunction();
62 }
63 }
64
65 public void ReturnObject(T obj)
66 {
67 lock (m_pool)
68 {
69 if (m_pool.Count >= m_maxPoolSize)
70 return;
71 else
72 m_pool.Push(obj);
73 }
74 }
75 }
76} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 1d304db..7820caf 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -192,7 +192,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
192 /// </summary> 192 /// </summary>
193 private IClientAPI m_currentIncomingClient; 193 private IClientAPI m_currentIncomingClient;
194 194
195 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 195 public LLUDPServer(
196 IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
197 IConfigSource configSource, AgentCircuitManager circuitManager)
196 : base(listenIP, (int)port) 198 : base(listenIP, (int)port)
197 { 199 {
198 #region Environment.TickCount Measurement 200 #region Environment.TickCount Measurement
@@ -246,6 +248,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
246 { 248 {
247 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true); 249 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
248 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true); 250 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
251 UsePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", false);
249 } 252 }
250 253
251 #region BinaryStats 254 #region BinaryStats
@@ -288,8 +291,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
288 private void StartInbound() 291 private void StartInbound()
289 { 292 {
290 m_log.InfoFormat( 293 m_log.InfoFormat(
291 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode", 294 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
292 m_asyncPacketHandling ? "asynchronous" : "synchronous"); 295 m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
293 296
294 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling); 297 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
295 298
@@ -304,7 +307,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
304 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 307 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
305 } 308 }
306 309
307 private void StartOutbound() 310 private new void StartOutbound()
308 { 311 {
309 m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server"); 312 m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
310 313
@@ -321,7 +324,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
321 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 324 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
322 } 325 }
323 326
324 public new void Stop() 327 public void Stop()
325 { 328 {
326 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); 329 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
327 base.StopOutbound(); 330 base.StopOutbound();
@@ -810,7 +813,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
810 LLUDPClient udpClient = null; 813 LLUDPClient udpClient = null;
811 Packet packet = null; 814 Packet packet = null;
812 int packetEnd = buffer.DataLength - 1; 815 int packetEnd = buffer.DataLength - 1;
813 IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; 816 IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
814 817
815 #region Decoding 818 #region Decoding
816 819
@@ -820,7 +823,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
820// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", 823// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
821// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 824// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
822 825
823 return; // Drop undersizd packet 826 return; // Drop undersized packet
824 } 827 }
825 828
826 int headerLen = 7; 829 int headerLen = 7;
@@ -846,6 +849,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
846// packet = Packet.BuildPacket(buffer.Data, ref packetEnd, 849// packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
847// // Only allocate a buffer for zerodecoding if the packet is zerocoded 850// // Only allocate a buffer for zerodecoding if the packet is zerocoded
848// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 851// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
852 // If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we
853 // assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all
854 // bytes are copied out).
849 packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd, 855 packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
850 // Only allocate a buffer for zerodecoding if the packet is zerocoded 856 // Only allocate a buffer for zerodecoding if the packet is zerocoded
851 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 857 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
@@ -887,7 +893,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
887 893
888 // If there is already a client for this endpoint, don't process UseCircuitCode 894 // If there is already a client for this endpoint, don't process UseCircuitCode
889 IClientAPI client = null; 895 IClientAPI client = null;
890 if (!m_scene.TryGetClient(address, out client)) 896 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
891 { 897 {
892 // UseCircuitCode handling 898 // UseCircuitCode handling
893 if (packet.Type == PacketType.UseCircuitCode) 899 if (packet.Type == PacketType.UseCircuitCode)
@@ -895,13 +901,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
895 // And if there is a UseCircuitCode pending, also drop it 901 // And if there is a UseCircuitCode pending, also drop it
896 lock (m_pendingCache) 902 lock (m_pendingCache)
897 { 903 {
898 if (m_pendingCache.Contains(address)) 904 if (m_pendingCache.Contains(endPoint))
899 return; 905 return;
900 906
901 m_pendingCache.AddOrUpdate(address, new Queue<UDPPacketBuffer>(), 60); 907 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
902 } 908 }
903 909
904 object[] array = new object[] { buffer, packet }; 910 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
911 // buffer.
912 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
905 913
906 Util.FireAndForget(HandleUseCircuitCode, array); 914 Util.FireAndForget(HandleUseCircuitCode, array);
907 915
@@ -913,7 +921,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
913 lock (m_pendingCache) 921 lock (m_pendingCache)
914 { 922 {
915 Queue<UDPPacketBuffer> queue; 923 Queue<UDPPacketBuffer> queue;
916 if (m_pendingCache.TryGetValue(address, out queue)) 924 if (m_pendingCache.TryGetValue(endPoint, out queue))
917 { 925 {
918 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); 926 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
919 queue.Enqueue(buffer); 927 queue.Enqueue(buffer);
@@ -1128,21 +1136,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1128 1136
1129 private void HandleUseCircuitCode(object o) 1137 private void HandleUseCircuitCode(object o)
1130 { 1138 {
1131 IPEndPoint remoteEndPoint = null; 1139 IPEndPoint endPoint = null;
1132 IClientAPI client = null; 1140 IClientAPI client = null;
1133 1141
1134 try 1142 try
1135 { 1143 {
1136 // DateTime startTime = DateTime.Now; 1144 // DateTime startTime = DateTime.Now;
1137 object[] array = (object[])o; 1145 object[] array = (object[])o;
1138 UDPPacketBuffer buffer = (UDPPacketBuffer)array[0]; 1146 endPoint = (IPEndPoint)array[0];
1139 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; 1147 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
1140 1148
1141 m_log.DebugFormat( 1149 m_log.DebugFormat(
1142 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", 1150 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
1143 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint); 1151 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint);
1144
1145 remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
1146 1152
1147 AuthenticateResponse sessionInfo; 1153 AuthenticateResponse sessionInfo;
1148 if (IsClientAuthorized(uccp, out sessionInfo)) 1154 if (IsClientAuthorized(uccp, out sessionInfo))
@@ -1153,13 +1159,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1153 uccp.CircuitCode.Code, 1159 uccp.CircuitCode.Code,
1154 uccp.CircuitCode.ID, 1160 uccp.CircuitCode.ID,
1155 uccp.CircuitCode.SessionID, 1161 uccp.CircuitCode.SessionID,
1156 remoteEndPoint, 1162 endPoint,
1157 sessionInfo); 1163 sessionInfo);
1158 1164
1159 // Send ack straight away to let the viewer know that the connection is active. 1165 // Send ack straight away to let the viewer know that the connection is active.
1160 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use 1166 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1161 // circuit code to the existing child agent. This is not particularly obvious. 1167 // circuit code to the existing child agent. This is not particularly obvious.
1162 SendAckImmediate(remoteEndPoint, uccp.Header.Sequence); 1168 SendAckImmediate(endPoint, uccp.Header.Sequence);
1163 1169
1164 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1170 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1165 if (client != null) 1171 if (client != null)
@@ -1173,12 +1179,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1173 1179
1174 lock (m_pendingCache) 1180 lock (m_pendingCache)
1175 { 1181 {
1176 if (!m_pendingCache.TryGetValue(remoteEndPoint, out queue)) 1182 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1177 { 1183 {
1178 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); 1184 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1179 return; 1185 return;
1180 } 1186 }
1181 m_pendingCache.Remove(remoteEndPoint); 1187 m_pendingCache.Remove(endPoint);
1182 } 1188 }
1183 1189
1184 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); 1190 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
@@ -1196,9 +1202,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1196 // Don't create clients for unauthorized requesters. 1202 // Don't create clients for unauthorized requesters.
1197 m_log.WarnFormat( 1203 m_log.WarnFormat(
1198 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1204 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1199 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); 1205 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1200 lock (m_pendingCache) 1206 lock (m_pendingCache)
1201 m_pendingCache.Remove(remoteEndPoint); 1207 m_pendingCache.Remove(endPoint);
1202 } 1208 }
1203 1209
1204 // m_log.DebugFormat( 1210 // m_log.DebugFormat(
@@ -1210,7 +1216,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1210 { 1216 {
1211 m_log.ErrorFormat( 1217 m_log.ErrorFormat(
1212 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", 1218 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1213 remoteEndPoint != null ? remoteEndPoint.ToString() : "n/a", 1219 endPoint != null ? endPoint.ToString() : "n/a",
1214 client != null ? client.Name : "unknown", 1220 client != null ? client.Name : "unknown",
1215 client != null ? client.AgentId.ToString() : "unknown", 1221 client != null ? client.AgentId.ToString() : "unknown",
1216 e.Message, 1222 e.Message,
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 82775fd..e7d8a30 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -30,6 +30,7 @@ using System.Net;
30using System.Net.Sockets; 30using System.Net.Sockets;
31using System.Threading; 31using System.Threading;
32using log4net; 32using log4net;
33using OpenSim.Framework;
33 34
34namespace OpenMetaverse 35namespace OpenMetaverse
35{ 36{
@@ -58,6 +59,16 @@ namespace OpenMetaverse
58 /// <summary>Flag to process packets asynchronously or synchronously</summary> 59 /// <summary>Flag to process packets asynchronously or synchronously</summary>
59 private bool m_asyncPacketHandling; 60 private bool m_asyncPacketHandling;
60 61
62 /// <summary>
63 /// Pool to use for handling data. May be null if UsePools = false;
64 /// </summary>
65 protected OpenSim.Framework.Pool<UDPPacketBuffer> m_pool;
66
67 /// <summary>
68 /// Are we to use object pool(s) to reduce memory churn when receiving data?
69 /// </summary>
70 public bool UsePools { get; protected set; }
71
61 /// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary> 72 /// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary>
62 public bool IsRunningInbound { get; private set; } 73 public bool IsRunningInbound { get; private set; }
63 74
@@ -70,6 +81,7 @@ namespace OpenMetaverse
70 /// </summary> 81 /// </summary>
71 /// <param name="bindAddress">Local IP address to bind the server to</param> 82 /// <param name="bindAddress">Local IP address to bind the server to</param>
72 /// <param name="port">Port to listening for incoming UDP packets on</param> 83 /// <param name="port">Port to listening for incoming UDP packets on</param>
84 /// /// <param name="usePool">Are we to use an object pool to get objects for handing inbound data?</param>
73 public OpenSimUDPBase(IPAddress bindAddress, int port) 85 public OpenSimUDPBase(IPAddress bindAddress, int port)
74 { 86 {
75 m_localBindAddress = bindAddress; 87 m_localBindAddress = bindAddress;
@@ -94,6 +106,11 @@ namespace OpenMetaverse
94 /// necessary</remarks> 106 /// necessary</remarks>
95 public void StartInbound(int recvBufferSize, bool asyncPacketHandling) 107 public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
96 { 108 {
109 if (UsePools)
110 m_pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
111 else
112 m_pool = null;
113
97 m_asyncPacketHandling = asyncPacketHandling; 114 m_asyncPacketHandling = asyncPacketHandling;
98 115
99 if (!IsRunningInbound) 116 if (!IsRunningInbound)
@@ -161,9 +178,12 @@ namespace OpenMetaverse
161 178
162 private void AsyncBeginReceive() 179 private void AsyncBeginReceive()
163 { 180 {
164 // allocate a packet buffer 181 UDPPacketBuffer buf;
165 //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); 182
166 UDPPacketBuffer buf = new UDPPacketBuffer(); 183 if (UsePools)
184 buf = m_pool.GetObject();
185 else
186 buf = new UDPPacketBuffer();
167 187
168 if (IsRunningInbound) 188 if (IsRunningInbound)
169 { 189 {
@@ -227,8 +247,6 @@ namespace OpenMetaverse
227 247
228 // get the buffer that was created in AsyncBeginReceive 248 // get the buffer that was created in AsyncBeginReceive
229 // this is the received data 249 // this is the received data
230 //WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState;
231 //UDPPacketBuffer buffer = wrappedBuffer.Instance;
232 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; 250 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
233 251
234 try 252 try
@@ -245,7 +263,8 @@ namespace OpenMetaverse
245 catch (ObjectDisposedException) { } 263 catch (ObjectDisposedException) { }
246 finally 264 finally
247 { 265 {
248 //wrappedBuffer.Dispose(); 266 if (UsePools)
267 m_pool.ReturnObject(buffer);
249 268
250 // Synchronous mode waits until the packet callback completes 269 // Synchronous mode waits until the packet callback completes
251 // before starting the receive to fetch another packet 270 // before starting the receive to fetch another packet