diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 394 |
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 | } |