diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | 139 |
1 files changed, 85 insertions, 54 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index f62dc15..f362b06 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | |||
@@ -3,25 +3,25 @@ | |||
3 | * Original Author: Jeff Cesnik | 3 | * Original Author: Jeff Cesnik |
4 | * All rights reserved. | 4 | * All rights reserved. |
5 | * | 5 | * |
6 | * - Redistribution and use in source and binary forms, with or without | 6 | * - Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions are met: | 7 | * modification, are permitted provided that the following conditions are met: |
8 | * | 8 | * |
9 | * - Redistributions of source code must retain the above copyright notice, this | 9 | * - Redistributions of source code must retain the above copyright notice, this |
10 | * list of conditions and the following disclaimer. | 10 | * list of conditions and the following disclaimer. |
11 | * - Neither the name of the openmetaverse.org nor the names | 11 | * - Neither the name of the openmetaverse.org nor the names |
12 | * of its contributors may be used to endorse or promote products derived from | 12 | * of its contributors may be used to endorse or promote products derived from |
13 | * this software without specific prior written permission. | 13 | * this software without specific prior written permission. |
14 | * | 14 | * |
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 15 | * 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 | 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 23 | * 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 | 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
25 | * POSSIBILITY OF SUCH DAMAGE. | 25 | * POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
@@ -57,9 +57,6 @@ namespace OpenMetaverse | |||
57 | /// <summary>UDP socket, used in either client or server mode</summary> | 57 | /// <summary>UDP socket, used in either client or server mode</summary> |
58 | private Socket m_udpSocket; | 58 | private Socket m_udpSocket; |
59 | 59 | ||
60 | /// <summary>Flag to process packets asynchronously or synchronously</summary> | ||
61 | private bool m_asyncPacketHandling; | ||
62 | |||
63 | /// <summary> | 60 | /// <summary> |
64 | /// Are we to use object pool(s) to reduce memory churn when receiving data? | 61 | /// Are we to use object pool(s) to reduce memory churn when receiving data? |
65 | /// </summary> | 62 | /// </summary> |
@@ -107,13 +104,18 @@ namespace OpenMetaverse | |||
107 | /// </summary> | 104 | /// </summary> |
108 | public float AverageReceiveTicksForLastSamplePeriod { get; private set; } | 105 | public float AverageReceiveTicksForLastSamplePeriod { get; private set; } |
109 | 106 | ||
107 | public int Port | ||
108 | { | ||
109 | get { return m_udpPort; } | ||
110 | } | ||
111 | |||
110 | #region PacketDropDebugging | 112 | #region PacketDropDebugging |
111 | /// <summary> | 113 | /// <summary> |
112 | /// For debugging purposes only... random number generator for dropping | 114 | /// For debugging purposes only... random number generator for dropping |
113 | /// outbound packets. | 115 | /// outbound packets. |
114 | /// </summary> | 116 | /// </summary> |
115 | private Random m_dropRandomGenerator = new Random(); | 117 | private Random m_dropRandomGenerator = new Random(); |
116 | 118 | ||
117 | /// <summary> | 119 | /// <summary> |
118 | /// For debugging purposes only... parameters for a simplified | 120 | /// For debugging purposes only... parameters for a simplified |
119 | /// model of packet loss with bursts, overall drop rate should | 121 | /// model of packet loss with bursts, overall drop rate should |
@@ -132,7 +134,7 @@ namespace OpenMetaverse | |||
132 | /// </summary> | 134 | /// </summary> |
133 | private int m_dropLastTick = 0; | 135 | private int m_dropLastTick = 0; |
134 | private int m_dropResetTicks = 500; | 136 | private int m_dropResetTicks = 500; |
135 | 137 | ||
136 | /// <summary> | 138 | /// <summary> |
137 | /// Debugging code used to simulate dropped packets with bursts | 139 | /// Debugging code used to simulate dropped packets with bursts |
138 | /// </summary> | 140 | /// </summary> |
@@ -179,11 +181,16 @@ namespace OpenMetaverse | |||
179 | // m_dropRandomGenerator = new Random(); | 181 | // m_dropRandomGenerator = new Random(); |
180 | } | 182 | } |
181 | 183 | ||
184 | ~OpenSimUDPBase() | ||
185 | { | ||
186 | if(m_udpSocket !=null) | ||
187 | try { m_udpSocket.Close(); } catch { } | ||
188 | } | ||
182 | /// <summary> | 189 | /// <summary> |
183 | /// Start inbound UDP packet handling. | 190 | /// Start inbound UDP packet handling. |
184 | /// </summary> | 191 | /// </summary> |
185 | /// <param name="recvBufferSize">The size of the receive buffer for | 192 | /// <param name="recvBufferSize">The size of the receive buffer for |
186 | /// the UDP socket. This value is passed up to the operating system | 193 | /// the UDP socket. This value is passed up to the operating system |
187 | /// and used in the system networking stack. Use zero to leave this | 194 | /// and used in the system networking stack. Use zero to leave this |
188 | /// value as the default</param> | 195 | /// value as the default</param> |
189 | /// <param name="asyncPacketHandling">Set this to true to start | 196 | /// <param name="asyncPacketHandling">Set this to true to start |
@@ -195,10 +202,8 @@ namespace OpenMetaverse | |||
195 | /// manner (not throwing an exception when the remote side resets the | 202 | /// manner (not throwing an exception when the remote side resets the |
196 | /// connection). This call is ignored on Mono where the flag is not | 203 | /// connection). This call is ignored on Mono where the flag is not |
197 | /// necessary</remarks> | 204 | /// necessary</remarks> |
198 | public virtual void StartInbound(int recvBufferSize, bool asyncPacketHandling) | 205 | public virtual void StartInbound(int recvBufferSize) |
199 | { | 206 | { |
200 | m_asyncPacketHandling = asyncPacketHandling; | ||
201 | |||
202 | if (!IsRunningInbound) | 207 | if (!IsRunningInbound) |
203 | { | 208 | { |
204 | m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop"); | 209 | m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop"); |
@@ -206,10 +211,6 @@ namespace OpenMetaverse | |||
206 | const int SIO_UDP_CONNRESET = -1744830452; | 211 | const int SIO_UDP_CONNRESET = -1744830452; |
207 | 212 | ||
208 | IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); | 213 | IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); |
209 | |||
210 | m_log.DebugFormat( | ||
211 | "[UDPBASE]: Binding UDP listener using internal IP address config {0}:{1}", | ||
212 | ipep.Address, ipep.Port); | ||
213 | 214 | ||
214 | m_udpSocket = new Socket( | 215 | m_udpSocket = new Socket( |
215 | AddressFamily.InterNetwork, | 216 | AddressFamily.InterNetwork, |
@@ -227,14 +228,23 @@ namespace OpenMetaverse | |||
227 | { | 228 | { |
228 | m_log.Debug("[UDPBASE]: Failed to increase default TTL"); | 229 | m_log.Debug("[UDPBASE]: Failed to increase default TTL"); |
229 | } | 230 | } |
231 | |||
230 | try | 232 | try |
231 | { | 233 | { |
232 | // This udp socket flag is not supported under mono, | 234 | // This udp socket flag is not supported under mono, |
233 | // so we'll catch the exception and continue | 235 | // so we'll catch the exception and continue |
234 | m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); | 236 | // Try does not protect some mono versions on mac |
235 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set"); | 237 | if(Util.IsWindows()) |
238 | { | ||
239 | m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); | ||
240 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set"); | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); | ||
245 | } | ||
236 | } | 246 | } |
237 | catch (SocketException) | 247 | catch |
238 | { | 248 | { |
239 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); | 249 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); |
240 | } | 250 | } |
@@ -243,13 +253,22 @@ namespace OpenMetaverse | |||
243 | // we never want two regions to listen on the same port as they cannot demultiplex each other's messages, | 253 | // we never want two regions to listen on the same port as they cannot demultiplex each other's messages, |
244 | // leading to a confusing bug. | 254 | // leading to a confusing bug. |
245 | // By default, Windows does not allow two sockets to bind to the same port. | 255 | // By default, Windows does not allow two sockets to bind to the same port. |
246 | m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); | 256 | // |
257 | // Unfortunately, this also causes a crashed sim to leave the socket in a state | ||
258 | // where it appears to be in use but is really just hung from the old process | ||
259 | // crashing rather than closing it. While this protects agains misconfiguration, | ||
260 | // allowing crashed sims to be started up again right away, rather than having to | ||
261 | // wait 2 minutes for the socket to clear is more valuable. Commented 12/13/2016 | ||
262 | // m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); | ||
247 | 263 | ||
248 | if (recvBufferSize != 0) | 264 | if (recvBufferSize != 0) |
249 | m_udpSocket.ReceiveBufferSize = recvBufferSize; | 265 | m_udpSocket.ReceiveBufferSize = recvBufferSize; |
250 | 266 | ||
251 | m_udpSocket.Bind(ipep); | 267 | m_udpSocket.Bind(ipep); |
252 | 268 | ||
269 | if (m_udpPort == 0) | ||
270 | m_udpPort = ((IPEndPoint)m_udpSocket.LocalEndPoint).Port; | ||
271 | |||
253 | IsRunningInbound = true; | 272 | IsRunningInbound = true; |
254 | 273 | ||
255 | // kick off an async receive. The Start() method will return, the | 274 | // kick off an async receive. The Start() method will return, the |
@@ -319,7 +338,7 @@ namespace OpenMetaverse | |||
319 | { | 338 | { |
320 | UDPPacketBuffer buf; | 339 | UDPPacketBuffer buf; |
321 | 340 | ||
322 | // FIXME: Disabled for now as this causes issues with reused packet objects interfering with each other | 341 | // FIXME: Disabled for now as this causes issues with reused packet objects interfering with each other |
323 | // on Windows with m_asyncPacketHandling = true, though this has not been seen on Linux. | 342 | // on Windows with m_asyncPacketHandling = true, though this has not been seen on Linux. |
324 | // Possibly some unexpected issue with fetching UDP data concurrently with multiple threads. Requires more investigation. | 343 | // Possibly some unexpected issue with fetching UDP data concurrently with multiple threads. Requires more investigation. |
325 | // if (UsePools) | 344 | // if (UsePools) |
@@ -372,8 +391,8 @@ namespace OpenMetaverse | |||
372 | m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); | 391 | m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); |
373 | } | 392 | } |
374 | } | 393 | } |
375 | catch (ObjectDisposedException e) | 394 | catch (ObjectDisposedException e) |
376 | { | 395 | { |
377 | m_log.Error( | 396 | m_log.Error( |
378 | string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e); | 397 | string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e); |
379 | } | 398 | } |
@@ -392,12 +411,7 @@ namespace OpenMetaverse | |||
392 | if (IsRunningInbound) | 411 | if (IsRunningInbound) |
393 | { | 412 | { |
394 | UdpReceives++; | 413 | UdpReceives++; |
395 | 414 | ||
396 | // Asynchronous mode will start another receive before the | ||
397 | // callback for this packet is even fired. Very parallel :-) | ||
398 | if (m_asyncPacketHandling) | ||
399 | AsyncBeginReceive(); | ||
400 | |||
401 | try | 415 | try |
402 | { | 416 | { |
403 | // get the buffer that was created in AsyncBeginReceive | 417 | // get the buffer that was created in AsyncBeginReceive |
@@ -419,7 +433,7 @@ namespace OpenMetaverse | |||
419 | // since this should be rare and won't cause a runtime problem. | 433 | // since this should be rare and won't cause a runtime problem. |
420 | if (m_currentReceiveTimeSamples >= s_receiveTimeSamples) | 434 | if (m_currentReceiveTimeSamples >= s_receiveTimeSamples) |
421 | { | 435 | { |
422 | AverageReceiveTicksForLastSamplePeriod | 436 | AverageReceiveTicksForLastSamplePeriod |
423 | = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples; | 437 | = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples; |
424 | 438 | ||
425 | m_receiveTicksInCurrentSamplePeriod = 0; | 439 | m_receiveTicksInCurrentSamplePeriod = 0; |
@@ -431,16 +445,16 @@ namespace OpenMetaverse | |||
431 | m_currentReceiveTimeSamples++; | 445 | m_currentReceiveTimeSamples++; |
432 | } | 446 | } |
433 | } | 447 | } |
434 | catch (SocketException se) | 448 | catch (SocketException se) |
435 | { | 449 | { |
436 | m_log.Error( | 450 | m_log.Error( |
437 | string.Format( | 451 | string.Format( |
438 | "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ", | 452 | "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ", |
439 | UdpReceives, se.ErrorCode), | 453 | UdpReceives, se.ErrorCode), |
440 | se); | 454 | se); |
441 | } | 455 | } |
442 | catch (ObjectDisposedException e) | 456 | catch (ObjectDisposedException e) |
443 | { | 457 | { |
444 | m_log.Error( | 458 | m_log.Error( |
445 | string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e); | 459 | string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e); |
446 | } | 460 | } |
@@ -454,10 +468,7 @@ namespace OpenMetaverse | |||
454 | // if (UsePools) | 468 | // if (UsePools) |
455 | // Pool.ReturnObject(buffer); | 469 | // Pool.ReturnObject(buffer); |
456 | 470 | ||
457 | // Synchronous mode waits until the packet callback completes | 471 | AsyncBeginReceive(); |
458 | // before starting the receive to fetch another packet | ||
459 | if (!m_asyncPacketHandling) | ||
460 | AsyncBeginReceive(); | ||
461 | } | 472 | } |
462 | } | 473 | } |
463 | } | 474 | } |
@@ -471,7 +482,7 @@ namespace OpenMetaverse | |||
471 | // packets when testing throttles & retransmission code | 482 | // packets when testing throttles & retransmission code |
472 | // if (DropOutgoingPacket()) | 483 | // if (DropOutgoingPacket()) |
473 | // return; | 484 | // return; |
474 | 485 | ||
475 | try | 486 | try |
476 | { | 487 | { |
477 | m_udpSocket.BeginSendTo( | 488 | m_udpSocket.BeginSendTo( |
@@ -485,7 +496,7 @@ namespace OpenMetaverse | |||
485 | } | 496 | } |
486 | catch (SocketException) { } | 497 | catch (SocketException) { } |
487 | catch (ObjectDisposedException) { } | 498 | catch (ObjectDisposedException) { } |
488 | // } | 499 | // } |
489 | } | 500 | } |
490 | 501 | ||
491 | void AsyncEndSend(IAsyncResult result) | 502 | void AsyncEndSend(IAsyncResult result) |
@@ -500,5 +511,25 @@ namespace OpenMetaverse | |||
500 | catch (SocketException) { } | 511 | catch (SocketException) { } |
501 | catch (ObjectDisposedException) { } | 512 | catch (ObjectDisposedException) { } |
502 | } | 513 | } |
514 | |||
515 | public void SyncSend(UDPPacketBuffer buf) | ||
516 | { | ||
517 | try | ||
518 | { | ||
519 | m_udpSocket.SendTo( | ||
520 | buf.Data, | ||
521 | 0, | ||
522 | buf.DataLength, | ||
523 | SocketFlags.None, | ||
524 | buf.RemoteEndPoint | ||
525 | ); | ||
526 | UdpSends++; | ||
527 | } | ||
528 | catch (SocketException e) | ||
529 | { | ||
530 | m_log.Warn("[UDPBASE]: sync send SocketException {0} " + e.Message); | ||
531 | } | ||
532 | catch (ObjectDisposedException) { } | ||
533 | } | ||
503 | } | 534 | } |
504 | } \ No newline at end of file | 535 | } |