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