diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | 182 |
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 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Concurrent; | ||
29 | using System.Net; | 30 | using System.Net; |
30 | using System.Net.Sockets; | 31 | using System.Net.Sockets; |
31 | using System.Threading; | 32 | using 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 | } |