aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs415
1 files changed, 214 insertions, 201 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index c356f02..890f701 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -96,7 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
96 /// <summary>Incoming packets that are awaiting handling</summary> 96 /// <summary>Incoming packets that are awaiting handling</summary>
97 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 97 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
98 /// <summary></summary> 98 /// <summary></summary>
99 private UDPClientCollection clients = new UDPClientCollection(); 99 //private UDPClientCollection m_clients = new UDPClientCollection();
100 /// <summary>Bandwidth throttle for this UDP server</summary> 100 /// <summary>Bandwidth throttle for this UDP server</summary>
101 private TokenBucket m_throttle; 101 private TokenBucket m_throttle;
102 /// <summary>Bandwidth throttle rates for this UDP server</summary> 102 /// <summary>Bandwidth throttle rates for this UDP server</summary>
@@ -109,13 +109,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
109 private Location m_location; 109 private Location m_location;
110 /// <summary>The measured resolution of Environment.TickCount</summary> 110 /// <summary>The measured resolution of Environment.TickCount</summary>
111 private float m_tickCountResolution; 111 private float m_tickCountResolution;
112 /// <summary>The size of the receive buffer for the UDP socket. This value
113 /// is passed up to the operating system and used in the system networking
114 /// stack. Use zero to leave this value as the default</summary>
115 private int m_recvBufferSize;
112 116
113 /// <summary>The measured resolution of Environment.TickCount</summary> 117 /// <summary>The measured resolution of Environment.TickCount</summary>
114 public float TickCountResolution { get { return m_tickCountResolution; } } 118 public float TickCountResolution { get { return m_tickCountResolution; } }
115 public Socket Server { get { return null; } } 119 public Socket Server { get { return null; } }
116 120
117 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 121 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
118 : base((int)port) 122 : base(listenIP, (int)port)
119 { 123 {
120 #region Environment.TickCount Measurement 124 #region Environment.TickCount Measurement
121 125
@@ -134,18 +138,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
134 #endregion Environment.TickCount Measurement 138 #endregion Environment.TickCount Measurement
135 139
136 m_circuitManager = circuitManager; 140 m_circuitManager = circuitManager;
141 int sceneThrottleBps = 0;
137 142
138 // TODO: Config support for throttling the entire connection 143 IConfig config = configSource.Configs["ClientStack.LindenUDP"];
139 m_throttle = new TokenBucket(null, 0, 0); 144 if (config != null)
145 {
146 m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0);
147 sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0);
148 }
149
150 m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps);
140 m_throttleRates = new ThrottleRates(configSource); 151 m_throttleRates = new ThrottleRates(configSource);
141 } 152 }
142 153
143 public new void Start() 154 public void Start()
144 { 155 {
145 if (m_scene == null) 156 if (m_scene == null)
146 throw new InvalidOperationException("Cannot LLUDPServer.Start() without an IScene reference"); 157 throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference");
147 158
148 base.Start(); 159 base.Start(m_recvBufferSize);
149 160
150 // Start the incoming packet processing thread 161 // Start the incoming packet processing thread
151 Thread incomingThread = new Thread(IncomingPacketHandler); 162 Thread incomingThread = new Thread(IncomingPacketHandler);
@@ -181,24 +192,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
181 return x == m_location; 192 return x == m_location;
182 } 193 }
183 194
184 public void RemoveClient(IClientAPI client)
185 {
186 m_scene.ClientManager.Remove(client.CircuitCode);
187 client.Close(false);
188
189 LLUDPClient udpClient;
190 if (clients.TryGetValue(client.AgentId, out udpClient))
191 {
192 m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + client.Name + " in " + m_scene.RegionInfo.RegionName);
193 udpClient.Shutdown();
194 clients.Remove(client.AgentId, udpClient.RemoteEndPoint);
195 }
196 else
197 {
198 m_log.Warn("[LLUDPSERVER]: Failed to remove LLUDPClient for " + client.Name);
199 }
200 }
201
202 public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) 195 public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
203 { 196 {
204 // CoarseLocationUpdate packets cannot be split in an automated way 197 // CoarseLocationUpdate packets cannot be split in an automated way
@@ -216,30 +209,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
216 for (int i = 0; i < packetCount; i++) 209 for (int i = 0; i < packetCount; i++)
217 { 210 {
218 byte[] data = datas[i]; 211 byte[] data = datas[i];
219 clients.ForEach( 212 m_scene.ClientManager.ForEach(
220 delegate(LLUDPClient client) 213 delegate(IClientAPI client)
221 { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); 214 {
215 if (client is LLClientView)
216 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category);
217 }
218 );
222 } 219 }
223 } 220 }
224 else 221 else
225 { 222 {
226 byte[] data = packet.ToBytes(); 223 byte[] data = packet.ToBytes();
227 clients.ForEach( 224 m_scene.ClientManager.ForEach(
228 delegate(LLUDPClient client) 225 delegate(IClientAPI client)
229 { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); 226 {
227 if (client is LLClientView)
228 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category);
229 }
230 );
230 } 231 }
231 } 232 }
232 233
233 public void SendPacket(UUID agentID, Packet packet, ThrottleOutPacketType category, bool allowSplitting) 234 public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
234 {
235 LLUDPClient client;
236 if (clients.TryGetValue(agentID, out client))
237 SendPacket(client, packet, category, allowSplitting);
238 else
239 m_log.Warn("[LLUDPSERVER]: Attempted to send a packet to unknown agentID " + agentID);
240 }
241
242 public void SendPacket(LLUDPClient client, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
243 { 235 {
244 // CoarseLocationUpdate packets cannot be split in an automated way 236 // CoarseLocationUpdate packets cannot be split in an automated way
245 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) 237 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
@@ -256,25 +248,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
256 for (int i = 0; i < packetCount; i++) 248 for (int i = 0; i < packetCount; i++)
257 { 249 {
258 byte[] data = datas[i]; 250 byte[] data = datas[i];
259 SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); 251 SendPacketData(udpClient, data, packet.Type, category);
260 } 252 }
261 } 253 }
262 else 254 else
263 { 255 {
264 byte[] data = packet.ToBytes(); 256 byte[] data = packet.ToBytes();
265 SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); 257 SendPacketData(udpClient, data, packet.Type, category);
266 } 258 }
267 } 259 }
268 260
269 public void SendPacketData(LLUDPClient client, byte[] data, int dataLength, PacketType type, bool doZerocode, ThrottleOutPacketType category) 261 public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category)
270 { 262 {
263 int dataLength = data.Length;
264 bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
265
271 // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. 266 // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum.
272 // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting 267 // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting
273 // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here 268 // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here
274 // to accomodate for both common scenarios and provide ample room for ACK appending in both 269 // to accomodate for both common scenarios and provide ample room for ACK appending in both
275 int bufferSize = (dataLength > 180) ? Packet.MTU : 200; 270 int bufferSize = (dataLength > 180) ? Packet.MTU : 200;
276 271
277 UDPPacketBuffer buffer = new UDPPacketBuffer(client.RemoteEndPoint, bufferSize); 272 UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
278 273
279 // Zerocode if needed 274 // Zerocode if needed
280 if (doZerocode) 275 if (doZerocode)
@@ -285,17 +280,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
285 // The packet grew larger than the bufferSize while zerocoding. 280 // The packet grew larger than the bufferSize while zerocoding.
286 // Remove the MSG_ZEROCODED flag and send the unencoded data 281 // Remove the MSG_ZEROCODED flag and send the unencoded data
287 // instead 282 // instead
288 m_log.Info("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding. Removing MSG_ZEROCODED flag"); 283 m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". Removing MSG_ZEROCODED flag");
289 data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); 284 data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
290 //
291 buffer = new UDPPacketBuffer(client.RemoteEndPoint, dataLength);
292 //
293 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); 285 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
294 } 286 }
295 } 287 }
296 else 288 else
297 { 289 {
298 // ??? will it fit?
299 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); 290 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
300 } 291 }
301 buffer.DataLength = dataLength; 292 buffer.DataLength = dataLength;
@@ -303,7 +294,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
303 #region Queue or Send 294 #region Queue or Send
304 295
305 // Look up the UDPClient this is going to 296 // Look up the UDPClient this is going to
306 OutgoingPacket outgoingPacket = new OutgoingPacket(client, buffer, category); 297 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category);
307 298
308 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) 299 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
309 SendPacketFinal(outgoingPacket); 300 SendPacketFinal(outgoingPacket);
@@ -311,18 +302,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
311 #endregion Queue or Send 302 #endregion Queue or Send
312 } 303 }
313 304
314 public void SendAcks(LLUDPClient client) 305 public void SendAcks(LLUDPClient udpClient)
315 { 306 {
316 uint ack; 307 uint ack;
317 308
318 if (client.PendingAcks.Dequeue(out ack)) 309 if (udpClient.PendingAcks.Dequeue(out ack))
319 { 310 {
320 List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>(); 311 List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
321 PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); 312 PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock();
322 block.ID = ack; 313 block.ID = ack;
323 blocks.Add(block); 314 blocks.Add(block);
324 315
325 while (client.PendingAcks.Dequeue(out ack)) 316 while (udpClient.PendingAcks.Dequeue(out ack))
326 { 317 {
327 block = new PacketAckPacket.PacketsBlock(); 318 block = new PacketAckPacket.PacketsBlock();
328 block.ID = ack; 319 block.ID = ack;
@@ -333,22 +324,39 @@ namespace OpenSim.Region.ClientStack.LindenUDP
333 packet.Header.Reliable = false; 324 packet.Header.Reliable = false;
334 packet.Packets = blocks.ToArray(); 325 packet.Packets = blocks.ToArray();
335 326
336 SendPacket(client, packet, ThrottleOutPacketType.Unknown, true); 327 SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true);
337 } 328 }
338 } 329 }
339 330
340 public void SendPing(LLUDPClient client) 331 public void SendPing(LLUDPClient udpClient)
341 { 332 {
342 IClientAPI api = client.ClientAPI; 333 StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
343 if (api != null) 334 pc.Header.Reliable = false;
344 api.SendStartPingCheck(client.CurrentPingSequence++); 335
336 OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest();
337
338 pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++;
339 pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0;
340
341 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false);
345 } 342 }
346 343
347 public void ResendUnacked(LLUDPClient client) 344 public void ResendUnacked(LLUDPClient udpClient)
348 { 345 {
349 if (client.NeedAcks.Count > 0) 346 if (udpClient.IsConnected && udpClient.NeedAcks.Count > 0)
350 { 347 {
351 List<OutgoingPacket> expiredPackets = client.NeedAcks.GetExpiredPackets(client.RTO); 348 // Disconnect an agent if no packets are received for some time
349 //FIXME: Make 60 an .ini setting
350 if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60)
351 {
352 m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID);
353
354 RemoveClient(udpClient);
355 return;
356 }
357
358 // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO
359 List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
352 360
353 if (expiredPackets != null) 361 if (expiredPackets != null)
354 { 362 {
@@ -357,54 +365,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
357 { 365 {
358 OutgoingPacket outgoingPacket = expiredPackets[i]; 366 OutgoingPacket outgoingPacket = expiredPackets[i];
359 367
360 // FIXME: Make this an .ini setting 368 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
361 if (outgoingPacket.ResendCount < 3) 369 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
362 {
363 //Logger.Debug(String.Format("Resending packet #{0} (attempt {1}), {2}ms have passed",
364 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount));
365
366 // Set the resent flag
367 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
368 outgoingPacket.Category = ThrottleOutPacketType.Resend;
369 370
370 // The TickCount will be set to the current time when the packet 371 // Set the resent flag
371 // is actually sent out again 372 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
372 outgoingPacket.TickCount = 0; 373 outgoingPacket.Category = ThrottleOutPacketType.Resend;
373 374
374 // Bump up the resend count on this packet 375 // The TickCount will be set to the current time when the packet
375 Interlocked.Increment(ref outgoingPacket.ResendCount); 376 // is actually sent out again
376 //Interlocked.Increment(ref Stats.ResentPackets); 377 outgoingPacket.TickCount = 0;
377 378
378 // Queue or (re)send the packet 379 // Bump up the resend count on this packet
379 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) 380 Interlocked.Increment(ref outgoingPacket.ResendCount);
380 SendPacketFinal(outgoingPacket); 381 //Interlocked.Increment(ref Stats.ResentPackets);
381 }
382 else
383 {
384 m_log.DebugFormat("[LLUDPSERVER]: Dropping packet #{0} for agent {1} after {2} failed attempts",
385 outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount);
386 382
387 lock (client.NeedAcks.SyncRoot) 383 // Requeue or resend the packet
388 client.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber); 384 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
389 385 SendPacketFinal(outgoingPacket);
390 //Interlocked.Increment(ref Stats.DroppedPackets);
391
392 // Disconnect an agent if no packets are received for some time
393 //FIXME: Make 60 an .ini setting
394 if (Environment.TickCount - client.TickLastPacketReceived > 1000 * 60)
395 {
396 m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + client.ClientAPI.Name);
397
398 RemoveClient(client.ClientAPI);
399 return;
400 }
401 }
402 } 386 }
403 } 387 }
404 } 388 }
405 } 389 }
406 390
407 public void Flush() 391 public void Flush(LLUDPClient udpClient)
408 { 392 {
409 // FIXME: Implement? 393 // FIXME: Implement?
410 } 394 }
@@ -415,7 +399,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
415 byte flags = buffer.Data[0]; 399 byte flags = buffer.Data[0];
416 bool isResend = (flags & Helpers.MSG_RESENT) != 0; 400 bool isResend = (flags & Helpers.MSG_RESENT) != 0;
417 bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; 401 bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;
418 LLUDPClient client = outgoingPacket.Client; 402 LLUDPClient udpClient = outgoingPacket.Client;
403
404 if (!udpClient.IsConnected)
405 return;
419 406
420 // Keep track of when this packet was sent out (right now) 407 // Keep track of when this packet was sent out (right now)
421 outgoingPacket.TickCount = Environment.TickCount; 408 outgoingPacket.TickCount = Environment.TickCount;
@@ -424,11 +411,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
424 411
425 int dataLength = buffer.DataLength; 412 int dataLength = buffer.DataLength;
426 413
427 // Keep appending ACKs until there is no room left in the packet or there are 414 // Keep appending ACKs until there is no room left in the buffer or there are
428 // no more ACKs to append 415 // no more ACKs to append
429 uint ackCount = 0; 416 uint ackCount = 0;
430 uint ack; 417 uint ack;
431 while (dataLength + 5 < buffer.Data.Length && client.PendingAcks.Dequeue(out ack)) 418 while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack))
432 { 419 {
433 Utils.UIntToBytesBig(ack, buffer.Data, dataLength); 420 Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
434 dataLength += 4; 421 dataLength += 4;
@@ -447,24 +434,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
447 434
448 #endregion ACK Appending 435 #endregion ACK Appending
449 436
437 #region Sequence Number Assignment
438
450 if (!isResend) 439 if (!isResend)
451 { 440 {
452 // Not a resend, assign a new sequence number 441 // Not a resend, assign a new sequence number
453 uint sequenceNumber = (uint)Interlocked.Increment(ref client.CurrentSequence); 442 uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence);
454 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); 443 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
455 outgoingPacket.SequenceNumber = sequenceNumber; 444 outgoingPacket.SequenceNumber = sequenceNumber;
456 445
457 if (isReliable) 446 if (isReliable)
458 { 447 {
459 // Add this packet to the list of ACK responses we are waiting on from the server 448 // Add this packet to the list of ACK responses we are waiting on from the server
460 client.NeedAcks.Add(outgoingPacket); 449 udpClient.NeedAcks.Add(outgoingPacket);
461 } 450 }
462 } 451 }
463 452
453 #endregion Sequence Number Assignment
454
464 // Stats tracking 455 // Stats tracking
465 Interlocked.Increment(ref client.PacketsSent); 456 Interlocked.Increment(ref udpClient.PacketsSent);
466 if (isReliable) 457 if (isReliable)
467 Interlocked.Add(ref client.UnackedBytes, outgoingPacket.Buffer.DataLength); 458 Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength);
468 459
469 // Put the UDP payload on the wire 460 // Put the UDP payload on the wire
470 AsyncBeginSend(buffer); 461 AsyncBeginSend(buffer);
@@ -473,10 +464,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
473 protected override void PacketReceived(UDPPacketBuffer buffer) 464 protected override void PacketReceived(UDPPacketBuffer buffer)
474 { 465 {
475 // Debugging/Profiling 466 // Debugging/Profiling
476 //try { Thread.CurrentThread.Name = "PacketReceived (" + scene.RegionName + ")"; } 467 //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; }
477 //catch (Exception) { } 468 //catch (Exception) { }
478 469
479 LLUDPClient client = null; 470 LLUDPClient udpClient = null;
480 Packet packet = null; 471 Packet packet = null;
481 int packetEnd = buffer.DataLength - 1; 472 int packetEnd = buffer.DataLength - 1;
482 IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; 473 IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint;
@@ -491,61 +482,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP
491 } 482 }
492 catch (MalformedDataException) 483 catch (MalformedDataException)
493 { 484 {
494 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet:\n{0}", 485 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet from {0}:\n{1}",
495 Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); 486 buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
496 } 487 }
497 488
498 // Fail-safe check 489 // Fail-safe check
499 if (packet == null) 490 if (packet == null)
500 { 491 {
501 m_log.Warn("[LLUDPSERVER]: Couldn't build a message from the incoming data"); 492 m_log.Warn("[LLUDPSERVER]: Couldn't build a message from incoming data " + buffer.DataLength +
493 " bytes long from " + buffer.RemoteEndPoint);
502 return; 494 return;
503 } 495 }
504 496
505 //Stats.RecvBytes += (ulong)buffer.DataLength;
506 //++Stats.RecvPackets;
507
508 #endregion Decoding 497 #endregion Decoding
509 498
510 #region UseCircuitCode Handling 499 #region Packet to Client Mapping
511 500
501 // UseCircuitCode handling
512 if (packet.Type == PacketType.UseCircuitCode) 502 if (packet.Type == PacketType.UseCircuitCode)
513 { 503 {
514 UseCircuitCodePacket useCircuitCode = (UseCircuitCodePacket)packet; 504 AddNewClient((UseCircuitCodePacket)packet, (IPEndPoint)buffer.RemoteEndPoint);
515 IClientAPI newuser;
516 uint circuitCode = useCircuitCode.CircuitCode.Code;
517
518 // Check if the client is already established
519 if (!m_scene.ClientManager.TryGetClient(circuitCode, out newuser))
520 {
521 AddNewClient(useCircuitCode, (IPEndPoint)buffer.RemoteEndPoint);
522 }
523 } 505 }
524 506
525 // Determine which agent this packet came from 507 // Determine which agent this packet came from
526 if (!clients.TryGetValue(address, out client)) 508 IClientAPI client;
509 if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView))
527 { 510 {
528 m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 511 m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address +
512 " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients");
529 return; 513 return;
530 } 514 }
531 515
532 #endregion UseCircuitCode Handling 516 udpClient = ((LLClientView)client).UDPClient;
517
518 if (!udpClient.IsConnected)
519 return;
520
521 #endregion Packet to Client Mapping
533 522
534 // Stats tracking 523 // Stats tracking
535 Interlocked.Increment(ref client.PacketsReceived); 524 Interlocked.Increment(ref udpClient.PacketsReceived);
536 525
537 #region ACK Receiving 526 #region ACK Receiving
538 527
539 int now = Environment.TickCount; 528 int now = Environment.TickCount;
540 client.TickLastPacketReceived = now; 529 udpClient.TickLastPacketReceived = now;
541 530
542 // Handle appended ACKs 531 // Handle appended ACKs
543 if (packet.Header.AppendedAcks && packet.Header.AckList != null) 532 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
544 { 533 {
545 lock (client.NeedAcks.SyncRoot) 534 lock (udpClient.NeedAcks.SyncRoot)
546 { 535 {
547 for (int i = 0; i < packet.Header.AckList.Length; i++) 536 for (int i = 0; i < packet.Header.AckList.Length; i++)
548 AcknowledgePacket(client, packet.Header.AckList[i], now, packet.Header.Resent); 537 AcknowledgePacket(udpClient, packet.Header.AckList[i], now, packet.Header.Resent);
549 } 538 }
550 } 539 }
551 540
@@ -554,10 +543,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
554 { 543 {
555 PacketAckPacket ackPacket = (PacketAckPacket)packet; 544 PacketAckPacket ackPacket = (PacketAckPacket)packet;
556 545
557 lock (client.NeedAcks.SyncRoot) 546 lock (udpClient.NeedAcks.SyncRoot)
558 { 547 {
559 for (int i = 0; i < ackPacket.Packets.Length; i++) 548 for (int i = 0; i < ackPacket.Packets.Length; i++)
560 AcknowledgePacket(client, ackPacket.Packets[i].ID, now, packet.Header.Resent); 549 AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent);
561 } 550 }
562 } 551 }
563 552
@@ -566,27 +555,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
566 #region ACK Sending 555 #region ACK Sending
567 556
568 if (packet.Header.Reliable) 557 if (packet.Header.Reliable)
569 client.PendingAcks.Enqueue((uint)packet.Header.Sequence); 558 udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
570 559
571 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, 560 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
572 // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove 561 // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
573 // 2*MTU bytes from the value and send ACKs, and finally add the local value back to 562 // 2*MTU bytes from the value and send ACKs, and finally add the local value back to
574 // client.BytesSinceLastACK. Lockless thread safety 563 // client.BytesSinceLastACK. Lockless thread safety
575 int bytesSinceLastACK = Interlocked.Exchange(ref client.BytesSinceLastACK, 0); 564 int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
576 bytesSinceLastACK += buffer.DataLength; 565 bytesSinceLastACK += buffer.DataLength;
577 if (bytesSinceLastACK > Packet.MTU * 2) 566 if (bytesSinceLastACK > Packet.MTU * 2)
578 { 567 {
579 bytesSinceLastACK -= Packet.MTU * 2; 568 bytesSinceLastACK -= Packet.MTU * 2;
580 SendAcks(client); 569 SendAcks(udpClient);
581 } 570 }
582 Interlocked.Add(ref client.BytesSinceLastACK, bytesSinceLastACK); 571 Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
583 572
584 #endregion ACK Sending 573 #endregion ACK Sending
585 574
586 #region Incoming Packet Accounting 575 #region Incoming Packet Accounting
587 576
588 // Check the archive of received reliable packet IDs to see whether we already received this packet 577 // Check the archive of received reliable packet IDs to see whether we already received this packet
589 if (packet.Header.Reliable && !client.PacketArchive.TryEnqueue(packet.Header.Sequence)) 578 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
590 { 579 {
591 if (packet.Header.Resent) 580 if (packet.Header.Resent)
592 m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type); 581 m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type);
@@ -603,7 +592,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
603 if (packet.Type != PacketType.PacketAck) 592 if (packet.Type != PacketType.PacketAck)
604 { 593 {
605 // Inbox insertion 594 // Inbox insertion
606 packetInbox.Enqueue(new IncomingPacket(client, packet)); 595 packetInbox.Enqueue(new IncomingPacket(udpClient, packet));
607 } 596 }
608 } 597 }
609 598
@@ -623,53 +612,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP
623 612
624 private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint) 613 private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint)
625 { 614 {
626 //Slave regions don't accept new clients 615 UUID agentID = useCircuitCode.CircuitCode.ID;
616 UUID sessionID = useCircuitCode.CircuitCode.SessionID;
617 uint circuitCode = useCircuitCode.CircuitCode.Code;
618
627 if (m_scene.RegionStatus != RegionStatus.SlaveScene) 619 if (m_scene.RegionStatus != RegionStatus.SlaveScene)
628 { 620 {
629 AuthenticateResponse sessionInfo; 621 AuthenticateResponse sessionInfo;
630 bool isNewCircuit = !clients.ContainsKey(remoteEndPoint); 622 if (IsClientAuthorized(useCircuitCode, out sessionInfo))
631
632 if (!IsClientAuthorized(useCircuitCode, out sessionInfo))
633 { 623 {
634 m_log.WarnFormat( 624 AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo);
635 "[CONNECTION FAILURE]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
636 useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint);
637 return;
638 } 625 }
639 626 else
640 if (isNewCircuit)
641 { 627 {
642 UUID agentID = useCircuitCode.CircuitCode.ID; 628 // Don't create circuits for unauthorized clients
643 UUID sessionID = useCircuitCode.CircuitCode.SessionID; 629 m_log.WarnFormat(
644 uint circuitCode = useCircuitCode.CircuitCode.Code; 630 "[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
645 631 useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint);
646 AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo);
647 } 632 }
648 } 633 }
634 else
635 {
636 // Slave regions don't accept new clients
637 m_log.Debug("[LLUDPSERVER]: Slave region " + m_scene.RegionInfo.RegionName + " ignoring UseCircuitCode packet");
638 }
649 } 639 }
650 640
651 private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) 641 private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
652 { 642 {
653 // Create the LLUDPClient 643 // Create the LLUDPClient
654 LLUDPClient client = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint); 644 LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint);
655
656 // Create the LLClientView
657 LLClientView clientApi = new LLClientView(remoteEndPoint, m_scene, this, client, sessionInfo, agentID, sessionID, circuitCode);
658 clientApi.OnViewerEffect += m_scene.ClientManager.ViewerEffectHandler;
659 clientApi.OnLogout += LogoutHandler;
660 clientApi.OnConnectionClosed += RemoveClient;
661
662 // Start the IClientAPI
663 m_scene.ClientManager.Add(circuitCode, clientApi);
664 clientApi.Start();
665 645
666 // Give LLUDPClient a reference to IClientAPI 646 if (!m_scene.ClientManager.ContainsKey(agentID))
667 client.ClientAPI = clientApi; 647 {
648 // Create the LLClientView
649 LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
650 client.OnLogout += LogoutHandler;
668 651
669 // Add the new client to our list of tracked clients 652 // Start the IClientAPI
670 clients.Add(agentID, client.RemoteEndPoint, client); 653 client.Start();
654 }
655 else
656 {
657 m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}",
658 udpClient.AgentID, remoteEndPoint, circuitCode);
659 }
660 }
671 661
672 m_log.DebugFormat("[LLUDPSERVER]: Added new client {0} to region {1}", agentID, m_scene.RegionInfo.RegionName); 662 private void RemoveClient(LLUDPClient udpClient)
663 {
664 // Remove this client from the scene
665 IClientAPI client;
666 if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client))
667 client.Close();
673 } 668 }
674 669
675 private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend) 670 private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend)
@@ -747,20 +742,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
747 elapsed500MS = 0; 742 elapsed500MS = 0;
748 } 743 }
749 744
750 clients.ForEach( 745 m_scene.ClientManager.ForEach(
751 delegate(LLUDPClient client) 746 delegate(IClientAPI client)
752 { 747 {
753 if (client.DequeueOutgoing()) 748 if (client is LLClientView)
754 packetSent = true;
755 if (resendUnacked)
756 ResendUnacked(client);
757 if (sendAcks)
758 { 749 {
759 SendAcks(client); 750 LLUDPClient udpClient = ((LLClientView)client).UDPClient;
760 client.SendPacketStats(); 751
752 if (udpClient.IsConnected)
753 {
754 if (udpClient.DequeueOutgoing())
755 packetSent = true;
756 if (resendUnacked)
757 ResendUnacked(udpClient);
758 if (sendAcks)
759 {
760 SendAcks(udpClient);
761 udpClient.SendPacketStats();
762 }
763 if (sendPings)
764 SendPing(udpClient);
765 }
761 } 766 }
762 if (sendPings)
763 SendPing(client);
764 } 767 }
765 ); 768 );
766 769
@@ -773,38 +776,48 @@ namespace OpenSim.Region.ClientStack.LindenUDP
773 { 776 {
774 IncomingPacket incomingPacket = (IncomingPacket)state; 777 IncomingPacket incomingPacket = (IncomingPacket)state;
775 Packet packet = incomingPacket.Packet; 778 Packet packet = incomingPacket.Packet;
776 LLUDPClient client = incomingPacket.Client; 779 LLUDPClient udpClient = incomingPacket.Client;
780 IClientAPI client;
777 781
778 // Sanity check 782 // Sanity check
779 if (packet == null || client == null || client.ClientAPI == null) 783 if (packet == null || udpClient == null)
780 { 784 {
781 m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", Client=\"{1}\", Client.ClientAPI=\"{2}\"", 785 m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"",
782 packet, client, (client != null) ? client.ClientAPI : null); 786 packet, udpClient);
783 } 787 }
784 788
785 try 789 // Make sure this client is still alive
786 { 790 if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client))
787 // Process this packet
788 client.ClientAPI.ProcessInPacket(packet);
789 }
790 catch (ThreadAbortException)
791 { 791 {
792 // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down 792 try
793 m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); 793 {
794 Stop(); 794 // Process this packet
795 client.ProcessInPacket(packet);
796 }
797 catch (ThreadAbortException)
798 {
799 // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
800 m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
801 Stop();
802 }
803 catch (Exception e)
804 {
805 // Don't let a failure in an individual client thread crash the whole sim.
806 m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type);
807 m_log.Error(e.Message, e);
808 }
795 } 809 }
796 catch (Exception e) 810 else
797 { 811 {
798 // Don't let a failure in an individual client thread crash the whole sim. 812 m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID);
799 m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", client.AgentID, packet.Type);
800 m_log.Error(e.Message, e);
801 } 813 }
802 } 814 }
803 815
804 private void LogoutHandler(IClientAPI client) 816 private void LogoutHandler(IClientAPI client)
805 { 817 {
806 client.SendLogoutPacket(); 818 client.SendLogoutPacket();
807 RemoveClient(client); 819 if (client.IsActive)
820 RemoveClient(((LLClientView)client).UDPClient);
808 } 821 }
809 } 822 }
810} 823}