aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs206
1 files changed, 185 insertions, 21 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index f143c32..f62dc15 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -78,6 +78,92 @@ namespace OpenMetaverse
78 public bool IsRunningOutbound { get; private set; } 78 public bool IsRunningOutbound { get; private set; }
79 79
80 /// <summary> 80 /// <summary>
81 /// Number of UDP receives.
82 /// </summary>
83 public int UdpReceives { get; private set; }
84
85 /// <summary>
86 /// Number of UDP sends
87 /// </summary>
88 public int UdpSends { get; private set; }
89
90 /// <summary>
91 /// Number of receives over which to establish a receive time average.
92 /// </summary>
93 private readonly static int s_receiveTimeSamples = 500;
94
95 /// <summary>
96 /// Current number of samples taken to establish a receive time average.
97 /// </summary>
98 private int m_currentReceiveTimeSamples;
99
100 /// <summary>
101 /// Cumulative receive time for the sample so far.
102 /// </summary>
103 private int m_receiveTicksInCurrentSamplePeriod;
104
105 /// <summary>
106 /// The average time taken for each require receive in the last sample.
107 /// </summary>
108 public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
109
110 #region PacketDropDebugging
111 /// <summary>
112 /// For debugging purposes only... random number generator for dropping
113 /// outbound packets.
114 /// </summary>
115 private Random m_dropRandomGenerator = new Random();
116
117 /// <summary>
118 /// For debugging purposes only... parameters for a simplified
119 /// model of packet loss with bursts, overall drop rate should
120 /// be roughly 1 - m_dropLengthProbability / (m_dropProbabiliy + m_dropLengthProbability)
121 /// which is about 1% for parameters 0.0015 and 0.15
122 /// </summary>
123 private double m_dropProbability = 0.0030;
124 private double m_dropLengthProbability = 0.15;
125 private bool m_dropState = false;
126
127 /// <summary>
128 /// For debugging purposes only... parameters to control the time
129 /// duration over which packet loss bursts can occur, if no packets
130 /// have been sent for m_dropResetTicks milliseconds, then reset the
131 /// state of the packet dropper to its default.
132 /// </summary>
133 private int m_dropLastTick = 0;
134 private int m_dropResetTicks = 500;
135
136 /// <summary>
137 /// Debugging code used to simulate dropped packets with bursts
138 /// </summary>
139 private bool DropOutgoingPacket()
140 {
141 double rnum = m_dropRandomGenerator.NextDouble();
142
143 // if the connection has been idle for awhile (more than m_dropResetTicks) then
144 // reset the state to the default state, don't continue a burst
145 int curtick = Util.EnvironmentTickCount();
146 if (Util.EnvironmentTickCountSubtract(curtick, m_dropLastTick) > m_dropResetTicks)
147 m_dropState = false;
148
149 m_dropLastTick = curtick;
150
151 // if we are dropping packets, then the probability of dropping
152 // this packet is the probability that we stay in the burst
153 if (m_dropState)
154 {
155 m_dropState = (rnum < (1.0 - m_dropLengthProbability)) ? true : false;
156 }
157 else
158 {
159 m_dropState = (rnum < m_dropProbability) ? true : false;
160 }
161
162 return m_dropState;
163 }
164 #endregion PacketDropDebugging
165
166 /// <summary>
81 /// Default constructor 167 /// Default constructor
82 /// </summary> 168 /// </summary>
83 /// <param name="bindAddress">Local IP address to bind the server to</param> 169 /// <param name="bindAddress">Local IP address to bind the server to</param>
@@ -87,6 +173,10 @@ namespace OpenMetaverse
87 { 173 {
88 m_localBindAddress = bindAddress; 174 m_localBindAddress = bindAddress;
89 m_udpPort = port; 175 m_udpPort = port;
176
177 // for debugging purposes only, initializes the random number generator
178 // used for simulating packet loss
179 // m_dropRandomGenerator = new Random();
90 } 180 }
91 181
92 /// <summary> 182 /// <summary>
@@ -105,12 +195,14 @@ namespace OpenMetaverse
105 /// manner (not throwing an exception when the remote side resets the 195 /// manner (not throwing an exception when the remote side resets the
106 /// connection). This call is ignored on Mono where the flag is not 196 /// connection). This call is ignored on Mono where the flag is not
107 /// necessary</remarks> 197 /// necessary</remarks>
108 public void StartInbound(int recvBufferSize, bool asyncPacketHandling) 198 public virtual void StartInbound(int recvBufferSize, bool asyncPacketHandling)
109 { 199 {
110 m_asyncPacketHandling = asyncPacketHandling; 200 m_asyncPacketHandling = asyncPacketHandling;
111 201
112 if (!IsRunningInbound) 202 if (!IsRunningInbound)
113 { 203 {
204 m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
205
114 const int SIO_UDP_CONNRESET = -1744830452; 206 const int SIO_UDP_CONNRESET = -1744830452;
115 207
116 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 208 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
@@ -126,6 +218,17 @@ namespace OpenMetaverse
126 218
127 try 219 try
128 { 220 {
221 if (m_udpSocket.Ttl < 128)
222 {
223 m_udpSocket.Ttl = 128;
224 }
225 }
226 catch (SocketException)
227 {
228 m_log.Debug("[UDPBASE]: Failed to increase default TTL");
229 }
230 try
231 {
129 // This udp socket flag is not supported under mono, 232 // This udp socket flag is not supported under mono,
130 // so we'll catch the exception and continue 233 // so we'll catch the exception and continue
131 m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); 234 m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null);
@@ -136,6 +239,12 @@ namespace OpenMetaverse
136 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); 239 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring");
137 } 240 }
138 241
242 // On at least Mono 3.2.8, multiple UDP sockets can bind to the same port by default. At the moment
243 // 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.
245 // By default, Windows does not allow two sockets to bind to the same port.
246 m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
247
139 if (recvBufferSize != 0) 248 if (recvBufferSize != 0)
140 m_udpSocket.ReceiveBufferSize = recvBufferSize; 249 m_udpSocket.ReceiveBufferSize = recvBufferSize;
141 250
@@ -153,30 +262,32 @@ namespace OpenMetaverse
153 /// <summary> 262 /// <summary>
154 /// Start outbound UDP packet handling. 263 /// Start outbound UDP packet handling.
155 /// </summary> 264 /// </summary>
156 public void StartOutbound() 265 public virtual void StartOutbound()
157 { 266 {
267 m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
268
158 IsRunningOutbound = true; 269 IsRunningOutbound = true;
159 } 270 }
160 271
161 public void StopInbound() 272 public virtual void StopInbound()
162 { 273 {
163 if (IsRunningInbound) 274 if (IsRunningInbound)
164 { 275 {
165 // wait indefinitely for a writer lock. Once this is called, the .NET runtime 276 m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
166 // will deny any more reader locks, in effect blocking all other send/receive 277
167 // threads. Once we have the lock, we set IsRunningInbound = false to inform the other
168 // threads that the socket is closed.
169 IsRunningInbound = false; 278 IsRunningInbound = false;
170 m_udpSocket.Close(); 279 m_udpSocket.Close();
171 } 280 }
172 } 281 }
173 282
174 public void StopOutbound() 283 public virtual void StopOutbound()
175 { 284 {
285 m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
286
176 IsRunningOutbound = false; 287 IsRunningOutbound = false;
177 } 288 }
178 289
179 protected virtual bool EnablePools() 290 public virtual bool EnablePools()
180 { 291 {
181 if (!UsePools) 292 if (!UsePools)
182 { 293 {
@@ -190,7 +301,7 @@ namespace OpenMetaverse
190 return false; 301 return false;
191 } 302 }
192 303
193 protected virtual bool DisablePools() 304 public virtual bool DisablePools()
194 { 305 {
195 if (UsePools) 306 if (UsePools)
196 { 307 {
@@ -261,7 +372,16 @@ namespace OpenMetaverse
261 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); 372 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
262 } 373 }
263 } 374 }
264 catch (ObjectDisposedException) { } 375 catch (ObjectDisposedException e)
376 {
377 m_log.Error(
378 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
379 }
380 catch (Exception e)
381 {
382 m_log.Error(
383 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
384 }
265 } 385 }
266 } 386 }
267 387
@@ -271,17 +391,21 @@ namespace OpenMetaverse
271 // to AsyncBeginReceive 391 // to AsyncBeginReceive
272 if (IsRunningInbound) 392 if (IsRunningInbound)
273 { 393 {
394 UdpReceives++;
395
274 // Asynchronous mode will start another receive before the 396 // Asynchronous mode will start another receive before the
275 // callback for this packet is even fired. Very parallel :-) 397 // callback for this packet is even fired. Very parallel :-)
276 if (m_asyncPacketHandling) 398 if (m_asyncPacketHandling)
277 AsyncBeginReceive(); 399 AsyncBeginReceive();
278 400
279 // get the buffer that was created in AsyncBeginReceive
280 // this is the received data
281 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
282
283 try 401 try
284 { 402 {
403 // get the buffer that was created in AsyncBeginReceive
404 // this is the received data
405 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
406
407 int startTick = Util.EnvironmentTickCount();
408
285 // get the length of data actually read from the socket, store it with the 409 // get the length of data actually read from the socket, store it with the
286 // buffer 410 // buffer
287 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); 411 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
@@ -289,9 +413,42 @@ namespace OpenMetaverse
289 // call the abstract method PacketReceived(), passing the buffer that 413 // call the abstract method PacketReceived(), passing the buffer that
290 // has just been filled from the socket read. 414 // has just been filled from the socket read.
291 PacketReceived(buffer); 415 PacketReceived(buffer);
416
417 // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
418 // then a particular stat may be inaccurate due to a race condition. We won't worry about this
419 // since this should be rare and won't cause a runtime problem.
420 if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
421 {
422 AverageReceiveTicksForLastSamplePeriod
423 = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
424
425 m_receiveTicksInCurrentSamplePeriod = 0;
426 m_currentReceiveTimeSamples = 0;
427 }
428 else
429 {
430 m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
431 m_currentReceiveTimeSamples++;
432 }
433 }
434 catch (SocketException se)
435 {
436 m_log.Error(
437 string.Format(
438 "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ",
439 UdpReceives, se.ErrorCode),
440 se);
441 }
442 catch (ObjectDisposedException e)
443 {
444 m_log.Error(
445 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
446 }
447 catch (Exception e)
448 {
449 m_log.Error(
450 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
292 } 451 }
293 catch (SocketException) { }
294 catch (ObjectDisposedException) { }
295 finally 452 finally
296 { 453 {
297// if (UsePools) 454// if (UsePools)
@@ -302,14 +459,19 @@ namespace OpenMetaverse
302 if (!m_asyncPacketHandling) 459 if (!m_asyncPacketHandling)
303 AsyncBeginReceive(); 460 AsyncBeginReceive();
304 } 461 }
305
306 } 462 }
307 } 463 }
308 464
309 public void AsyncBeginSend(UDPPacketBuffer buf) 465 public void AsyncBeginSend(UDPPacketBuffer buf)
310 { 466 {
311 if (IsRunningOutbound) 467// if (IsRunningOutbound)
312 { 468// {
469
470 // This is strictly for debugging purposes to simulate dropped
471 // packets when testing throttles & retransmission code
472 // if (DropOutgoingPacket())
473 // return;
474
313 try 475 try
314 { 476 {
315 m_udpSocket.BeginSendTo( 477 m_udpSocket.BeginSendTo(
@@ -323,7 +485,7 @@ namespace OpenMetaverse
323 } 485 }
324 catch (SocketException) { } 486 catch (SocketException) { }
325 catch (ObjectDisposedException) { } 487 catch (ObjectDisposedException) { }
326 } 488// }
327 } 489 }
328 490
329 void AsyncEndSend(IAsyncResult result) 491 void AsyncEndSend(IAsyncResult result)
@@ -332,6 +494,8 @@ namespace OpenMetaverse
332 { 494 {
333// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; 495// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
334 m_udpSocket.EndSendTo(result); 496 m_udpSocket.EndSendTo(result);
497
498 UdpSends++;
335 } 499 }
336 catch (SocketException) { } 500 catch (SocketException) { }
337 catch (ObjectDisposedException) { } 501 catch (ObjectDisposedException) { }