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.cs182
1 files changed, 79 insertions, 103 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index f362b06..49aca3c 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Concurrent;
29using System.Net; 30using System.Net;
30using System.Net.Sockets; 31using System.Net.Sockets;
31using System.Threading; 32using System.Threading;
@@ -57,15 +58,9 @@ namespace OpenMetaverse
57 /// <summary>UDP socket, used in either client or server mode</summary> 58 /// <summary>UDP socket, used in either client or server mode</summary>
58 private Socket m_udpSocket; 59 private Socket m_udpSocket;
59 60
60 /// <summary> 61 public static Object m_udpBuffersPoolLock = new Object();
61 /// Are we to use object pool(s) to reduce memory churn when receiving data? 62 public static UDPPacketBuffer[] m_udpBuffersPool = new UDPPacketBuffer[1000];
62 /// </summary> 63 public static int m_udpBuffersPoolPtr = -1;
63 public bool UsePools { get; protected set; }
64
65 /// <summary>
66 /// Pool to use for handling data. May be null if UsePools = false;
67 /// </summary>
68 protected OpenSim.Framework.Pool<UDPPacketBuffer> Pool { get; private set; }
69 64
70 /// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary> 65 /// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary>
71 public bool IsRunningInbound { get; private set; } 66 public bool IsRunningInbound { get; private set; }
@@ -186,6 +181,37 @@ namespace OpenMetaverse
186 if(m_udpSocket !=null) 181 if(m_udpSocket !=null)
187 try { m_udpSocket.Close(); } catch { } 182 try { m_udpSocket.Close(); } catch { }
188 } 183 }
184
185 public UDPPacketBuffer GetNewUDPBuffer(IPEndPoint remoteEndpoint)
186 {
187 lock (m_udpBuffersPoolLock)
188 {
189 if (m_udpBuffersPoolPtr >= 0)
190 {
191 UDPPacketBuffer buf = m_udpBuffersPool[m_udpBuffersPoolPtr];
192 m_udpBuffersPool[m_udpBuffersPoolPtr] = null;
193 m_udpBuffersPoolPtr--;
194 buf.RemoteEndPoint = remoteEndpoint;
195 return buf;
196 }
197 }
198 return new UDPPacketBuffer(remoteEndpoint);
199 }
200
201 public void FreeUDPBuffer(UDPPacketBuffer buf)
202 {
203 lock (m_udpBuffersPoolLock)
204 {
205 if (m_udpBuffersPoolPtr < 999)
206 {
207 buf.RemoteEndPoint = null;
208 buf.DataLength = 0;
209 m_udpBuffersPoolPtr++;
210 m_udpBuffersPool[m_udpBuffersPoolPtr] = buf;
211 }
212 }
213 }
214
189 /// <summary> 215 /// <summary>
190 /// Start inbound UDP packet handling. 216 /// Start inbound UDP packet handling.
191 /// </summary> 217 /// </summary>
@@ -202,6 +228,7 @@ namespace OpenMetaverse
202 /// manner (not throwing an exception when the remote side resets the 228 /// manner (not throwing an exception when the remote side resets the
203 /// connection). This call is ignored on Mono where the flag is not 229 /// connection). This call is ignored on Mono where the flag is not
204 /// necessary</remarks> 230 /// necessary</remarks>
231
205 public virtual void StartInbound(int recvBufferSize) 232 public virtual void StartInbound(int recvBufferSize)
206 { 233 {
207 if (!IsRunningInbound) 234 if (!IsRunningInbound)
@@ -306,102 +333,56 @@ namespace OpenMetaverse
306 IsRunningOutbound = false; 333 IsRunningOutbound = false;
307 } 334 }
308 335
309 public virtual bool EnablePools() 336 private void AsyncBeginReceive()
310 { 337 {
311 if (!UsePools) 338 if (!IsRunningInbound)
312 { 339 return;
313 Pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
314
315 UsePools = true;
316
317 return true;
318 }
319
320 return false;
321 }
322 340
323 public virtual bool DisablePools() 341 UDPPacketBuffer buf = GetNewUDPBuffer(new IPEndPoint(IPAddress.Any, 0)); // we need a fresh one here, for now at least
324 { 342 try
325 if (UsePools)
326 { 343 {
327 UsePools = false; 344 // kick off an async read
328 345 m_udpSocket.BeginReceiveFrom(
329 // We won't null out the pool to avoid a race condition with code that may be in the middle of using it. 346 buf.Data,
330 347 0,
331 return true; 348 buf.Data.Length,
349 SocketFlags.None,
350 ref buf.RemoteEndPoint,
351 AsyncEndReceive,
352 buf);
332 } 353 }
333 354 catch (SocketException e)
334 return false;
335 }
336
337 private void AsyncBeginReceive()
338 {
339 UDPPacketBuffer buf;
340
341 // FIXME: Disabled for now as this causes issues with reused packet objects interfering with each other
342 // on Windows with m_asyncPacketHandling = true, though this has not been seen on Linux.
343 // Possibly some unexpected issue with fetching UDP data concurrently with multiple threads. Requires more investigation.
344// if (UsePools)
345// buf = Pool.GetObject();
346// else
347 buf = new UDPPacketBuffer();
348
349 if (IsRunningInbound)
350 { 355 {
351 try 356 if (e.SocketErrorCode == SocketError.ConnectionReset)
352 {
353 // kick off an async read
354 m_udpSocket.BeginReceiveFrom(
355 //wrappedBuffer.Instance.Data,
356 buf.Data,
357 0,
358 UDPPacketBuffer.BUFFER_SIZE,
359 SocketFlags.None,
360 ref buf.RemoteEndPoint,
361 AsyncEndReceive,
362 //wrappedBuffer);
363 buf);
364 }
365 catch (SocketException e)
366 { 357 {
367 if (e.SocketErrorCode == SocketError.ConnectionReset) 358 m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort);
359 bool salvaged = false;
360 while (!salvaged)
368 { 361 {
369 m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort); 362 try
370 bool salvaged = false;
371 while (!salvaged)
372 { 363 {
373 try 364 m_udpSocket.BeginReceiveFrom(
374 { 365 buf.Data,
375 m_udpSocket.BeginReceiveFrom( 366 0,
376 //wrappedBuffer.Instance.Data, 367 buf.Data.Length,
377 buf.Data, 368 SocketFlags.None,
378 0, 369 ref buf.RemoteEndPoint,
379 UDPPacketBuffer.BUFFER_SIZE, 370 AsyncEndReceive,
380 SocketFlags.None, 371 buf);
381 ref buf.RemoteEndPoint, 372 salvaged = true;
382 AsyncEndReceive,
383 //wrappedBuffer);
384 buf);
385 salvaged = true;
386 }
387 catch (SocketException) { }
388 catch (ObjectDisposedException) { return; }
389 } 373 }
390 374 catch (SocketException) { }
391 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); 375 catch (ObjectDisposedException) { return; }
392 } 376 }
393 } 377
394 catch (ObjectDisposedException e) 378 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
395 {
396 m_log.Error(
397 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
398 }
399 catch (Exception e)
400 {
401 m_log.Error(
402 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
403 } 379 }
404 } 380 }
381 catch (Exception e)
382 {
383 m_log.Error(
384 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
385 }
405 } 386 }
406 387
407 private void AsyncEndReceive(IAsyncResult iar) 388 private void AsyncEndReceive(IAsyncResult iar)
@@ -453,11 +434,6 @@ namespace OpenMetaverse
453 UdpReceives, se.ErrorCode), 434 UdpReceives, se.ErrorCode),
454 se); 435 se);
455 } 436 }
456 catch (ObjectDisposedException e)
457 {
458 m_log.Error(
459 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
460 }
461 catch (Exception e) 437 catch (Exception e)
462 { 438 {
463 m_log.Error( 439 m_log.Error(
@@ -465,14 +441,12 @@ namespace OpenMetaverse
465 } 441 }
466 finally 442 finally
467 { 443 {
468// if (UsePools)
469// Pool.ReturnObject(buffer);
470
471 AsyncBeginReceive(); 444 AsyncBeginReceive();
472 } 445 }
473 } 446 }
474 } 447 }
475 448
449/* not in use
476 public void AsyncBeginSend(UDPPacketBuffer buf) 450 public void AsyncBeginSend(UDPPacketBuffer buf)
477 { 451 {
478// if (IsRunningOutbound) 452// if (IsRunningOutbound)
@@ -511,9 +485,11 @@ namespace OpenMetaverse
511 catch (SocketException) { } 485 catch (SocketException) { }
512 catch (ObjectDisposedException) { } 486 catch (ObjectDisposedException) { }
513 } 487 }
514 488*/
515 public void SyncSend(UDPPacketBuffer buf) 489 public void SyncSend(UDPPacketBuffer buf)
516 { 490 {
491 if(buf.RemoteEndPoint == null)
492 return; // already expired
517 try 493 try
518 { 494 {
519 m_udpSocket.SendTo( 495 m_udpSocket.SendTo(
@@ -527,7 +503,7 @@ namespace OpenMetaverse
527 } 503 }
528 catch (SocketException e) 504 catch (SocketException e)
529 { 505 {
530 m_log.Warn("[UDPBASE]: sync send SocketException {0} " + e.Message); 506 m_log.WarnFormat("[UDPBASE]: sync send SocketException {0} {1}", buf.RemoteEndPoint, e.Message);
531 } 507 }
532 catch (ObjectDisposedException) { } 508 catch (ObjectDisposedException) { }
533 } 509 }