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.cs139
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}