aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs116
1 files changed, 93 insertions, 23 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index cfe7c9d..8bd3461 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -30,6 +30,8 @@ using System.Net;
30using System.Net.Sockets; 30using System.Net.Sockets;
31using System.Threading; 31using System.Threading;
32using log4net; 32using log4net;
33using OpenSim.Framework;
34using OpenSim.Framework.Monitoring;
33 35
34namespace OpenMetaverse 36namespace OpenMetaverse
35{ 37{
@@ -58,17 +60,31 @@ namespace OpenMetaverse
58 /// <summary>Flag to process packets asynchronously or synchronously</summary> 60 /// <summary>Flag to process packets asynchronously or synchronously</summary>
59 private bool m_asyncPacketHandling; 61 private bool m_asyncPacketHandling;
60 62
61 /// <summary>The all important shutdown flag</summary> 63 /// <summary>
62 private volatile bool m_shutdownFlag = true; 64 /// Pool to use for handling data. May be null if UsePools = false;
65 /// </summary>
66 protected OpenSim.Framework.Pool<UDPPacketBuffer> m_pool;
67
68 /// <summary>
69 /// Are we to use object pool(s) to reduce memory churn when receiving data?
70 /// </summary>
71 public bool UsePools { get; protected set; }
72
73 /// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary>
74 public bool IsRunningInbound { get; private set; }
63 75
64 /// <summary>Returns true if the server is currently listening, otherwise false</summary> 76 /// <summary>Returns true if the server is currently sending outbound packets, otherwise false</summary>
65 public bool IsRunning { get { return !m_shutdownFlag; } } 77 /// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
78 public bool IsRunningOutbound { get; private set; }
79
80 private Stat m_poolCountStat;
66 81
67 /// <summary> 82 /// <summary>
68 /// Default constructor 83 /// Default constructor
69 /// </summary> 84 /// </summary>
70 /// <param name="bindAddress">Local IP address to bind the server to</param> 85 /// <param name="bindAddress">Local IP address to bind the server to</param>
71 /// <param name="port">Port to listening for incoming UDP packets on</param> 86 /// <param name="port">Port to listening for incoming UDP packets on</param>
87 /// /// <param name="usePool">Are we to use an object pool to get objects for handing inbound data?</param>
72 public OpenSimUDPBase(IPAddress bindAddress, int port) 88 public OpenSimUDPBase(IPAddress bindAddress, int port)
73 { 89 {
74 m_localBindAddress = bindAddress; 90 m_localBindAddress = bindAddress;
@@ -76,7 +92,7 @@ namespace OpenMetaverse
76 } 92 }
77 93
78 /// <summary> 94 /// <summary>
79 /// Start the UDP server 95 /// Start inbound UDP packet handling.
80 /// </summary> 96 /// </summary>
81 /// <param name="recvBufferSize">The size of the receive buffer for 97 /// <param name="recvBufferSize">The size of the receive buffer for
82 /// the UDP socket. This value is passed up to the operating system 98 /// the UDP socket. This value is passed up to the operating system
@@ -91,11 +107,11 @@ namespace OpenMetaverse
91 /// manner (not throwing an exception when the remote side resets the 107 /// manner (not throwing an exception when the remote side resets the
92 /// connection). This call is ignored on Mono where the flag is not 108 /// connection). This call is ignored on Mono where the flag is not
93 /// necessary</remarks> 109 /// necessary</remarks>
94 public void Start(int recvBufferSize, bool asyncPacketHandling) 110 public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
95 { 111 {
96 m_asyncPacketHandling = asyncPacketHandling; 112 m_asyncPacketHandling = asyncPacketHandling;
97 113
98 if (m_shutdownFlag) 114 if (!IsRunningInbound)
99 { 115 {
100 const int SIO_UDP_CONNRESET = -1744830452; 116 const int SIO_UDP_CONNRESET = -1744830452;
101 117
@@ -123,8 +139,7 @@ namespace OpenMetaverse
123 139
124 m_udpSocket.Bind(ipep); 140 m_udpSocket.Bind(ipep);
125 141
126 // we're not shutting down, we're starting up 142 IsRunningInbound = true;
127 m_shutdownFlag = false;
128 143
129 // kick off an async receive. The Start() method will return, the 144 // kick off an async receive. The Start() method will return, the
130 // actual receives will occur asynchronously and will be caught in 145 // actual receives will occur asynchronously and will be caught in
@@ -134,28 +149,84 @@ namespace OpenMetaverse
134 } 149 }
135 150
136 /// <summary> 151 /// <summary>
137 /// Stops the UDP server 152 /// Start outbound UDP packet handling.
138 /// </summary> 153 /// </summary>
139 public void Stop() 154 public void StartOutbound()
155 {
156 IsRunningOutbound = true;
157 }
158
159 public void StopInbound()
140 { 160 {
141 if (!m_shutdownFlag) 161 if (IsRunningInbound)
142 { 162 {
143 // wait indefinitely for a writer lock. Once this is called, the .NET runtime 163 // 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 164 // 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 165 // threads. Once we have the lock, we set IsRunningInbound = false to inform the other
146 // threads that the socket is closed. 166 // threads that the socket is closed.
147 m_shutdownFlag = true; 167 IsRunningInbound = false;
148 m_udpSocket.Close(); 168 m_udpSocket.Close();
149 } 169 }
150 } 170 }
151 171
172 public void StopOutbound()
173 {
174 IsRunningOutbound = false;
175 }
176
177 protected virtual bool EnablePools()
178 {
179 if (!UsePools)
180 {
181 m_pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
182
183 m_poolCountStat
184 = new Stat(
185 "UDPPacketBufferPoolCount",
186 "Objects within the UDPPacketBuffer pool",
187 "The number of objects currently stored within the UDPPacketBuffer pool",
188 "",
189 "clientstack",
190 "packetpool",
191 StatType.Pull,
192 stat => stat.Value = m_pool.Count,
193 StatVerbosity.Debug);
194
195 StatsManager.RegisterStat(m_poolCountStat);
196
197 UsePools = true;
198
199 return true;
200 }
201
202 return false;
203 }
204
205 protected virtual bool DisablePools()
206 {
207 if (UsePools)
208 {
209 UsePools = false;
210 StatsManager.DeregisterStat(m_poolCountStat);
211
212 // We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
213
214 return true;
215 }
216
217 return false;
218 }
219
152 private void AsyncBeginReceive() 220 private void AsyncBeginReceive()
153 { 221 {
154 // allocate a packet buffer 222 UDPPacketBuffer buf;
155 //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); 223
156 UDPPacketBuffer buf = new UDPPacketBuffer(); 224 if (UsePools)
225 buf = m_pool.GetObject();
226 else
227 buf = new UDPPacketBuffer();
157 228
158 if (!m_shutdownFlag) 229 if (IsRunningInbound)
159 { 230 {
160 try 231 try
161 { 232 {
@@ -208,7 +279,7 @@ namespace OpenMetaverse
208 { 279 {
209 // Asynchronous receive operations will complete here through the call 280 // Asynchronous receive operations will complete here through the call
210 // to AsyncBeginReceive 281 // to AsyncBeginReceive
211 if (!m_shutdownFlag) 282 if (IsRunningInbound)
212 { 283 {
213 // Asynchronous mode will start another receive before the 284 // Asynchronous mode will start another receive before the
214 // callback for this packet is even fired. Very parallel :-) 285 // callback for this packet is even fired. Very parallel :-)
@@ -217,8 +288,6 @@ namespace OpenMetaverse
217 288
218 // get the buffer that was created in AsyncBeginReceive 289 // get the buffer that was created in AsyncBeginReceive
219 // this is the received data 290 // this is the received data
220 //WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState;
221 //UDPPacketBuffer buffer = wrappedBuffer.Instance;
222 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; 291 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
223 292
224 try 293 try
@@ -235,7 +304,8 @@ namespace OpenMetaverse
235 catch (ObjectDisposedException) { } 304 catch (ObjectDisposedException) { }
236 finally 305 finally
237 { 306 {
238 //wrappedBuffer.Dispose(); 307 if (UsePools)
308 m_pool.ReturnObject(buffer);
239 309
240 // Synchronous mode waits until the packet callback completes 310 // Synchronous mode waits until the packet callback completes
241 // before starting the receive to fetch another packet 311 // before starting the receive to fetch another packet
@@ -248,7 +318,7 @@ namespace OpenMetaverse
248 318
249 public void AsyncBeginSend(UDPPacketBuffer buf) 319 public void AsyncBeginSend(UDPPacketBuffer buf)
250 { 320 {
251 if (!m_shutdownFlag) 321 if (IsRunningOutbound)
252 { 322 {
253 try 323 try
254 { 324 {