diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 138 |
1 files changed, 96 insertions, 42 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 7964c50..348615e 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | |||
@@ -35,6 +35,7 @@ using log4net; | |||
35 | using Nini.Config; | 35 | using Nini.Config; |
36 | using OpenMetaverse.Packets; | 36 | using OpenMetaverse.Packets; |
37 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
38 | using OpenSim.Framework.Statistics; | ||
38 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
39 | using OpenMetaverse; | 40 | using OpenMetaverse; |
40 | 41 | ||
@@ -190,31 +191,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
190 | } | 191 | } |
191 | } | 192 | } |
192 | 193 | ||
193 | public void RemoveClient(LLUDPClient udpClient) | ||
194 | { | ||
195 | IClientAPI client; | ||
196 | |||
197 | if (m_scene.ClientManager.TryGetClient(udpClient.CircuitCode, out client)) | ||
198 | RemoveClient(client); | ||
199 | else | ||
200 | m_log.Warn("[LLUDPSERVER]: Failed to lookup IClientAPI for LLUDPClient " + udpClient.AgentID); | ||
201 | } | ||
202 | |||
203 | public void SetClientPaused(UUID agentID, bool paused) | ||
204 | { | ||
205 | LLUDPClient client; | ||
206 | if (clients.TryGetValue(agentID, out client)) | ||
207 | { | ||
208 | client.IsPaused = paused; | ||
209 | } | ||
210 | else | ||
211 | { | ||
212 | m_log.Warn("[LLUDPSERVER]: Attempted to pause/unpause unknown agent " + agentID); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) | 194 | public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) |
217 | { | 195 | { |
196 | // CoarseLocationUpdate packets cannot be split in an automated way | ||
197 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) | ||
198 | allowSplitting = false; | ||
199 | |||
218 | if (allowSplitting && packet.HasVariableBlocks) | 200 | if (allowSplitting && packet.HasVariableBlocks) |
219 | { | 201 | { |
220 | byte[][] datas = packet.ToBytesMultiple(); | 202 | byte[][] datas = packet.ToBytesMultiple(); |
@@ -251,6 +233,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
251 | 233 | ||
252 | public void SendPacket(LLUDPClient client, Packet packet, ThrottleOutPacketType category, bool allowSplitting) | 234 | public void SendPacket(LLUDPClient client, Packet packet, ThrottleOutPacketType category, bool allowSplitting) |
253 | { | 235 | { |
236 | // CoarseLocationUpdate packets cannot be split in an automated way | ||
237 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) | ||
238 | allowSplitting = false; | ||
239 | |||
254 | if (allowSplitting && packet.HasVariableBlocks) | 240 | if (allowSplitting && packet.HasVariableBlocks) |
255 | { | 241 | { |
256 | byte[][] datas = packet.ToBytesMultiple(); | 242 | byte[][] datas = packet.ToBytesMultiple(); |
@@ -339,6 +325,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
339 | } | 325 | } |
340 | } | 326 | } |
341 | 327 | ||
328 | public void SendPing(LLUDPClient client) | ||
329 | { | ||
330 | IClientAPI api = client.ClientAPI; | ||
331 | if (api != null) | ||
332 | api.SendStartPingCheck(client.CurrentPingSequence++); | ||
333 | } | ||
334 | |||
342 | public void ResendUnacked(LLUDPClient client) | 335 | public void ResendUnacked(LLUDPClient client) |
343 | { | 336 | { |
344 | if (client.NeedAcks.Count > 0) | 337 | if (client.NeedAcks.Count > 0) |
@@ -387,9 +380,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
387 | //FIXME: Make 60 an .ini setting | 380 | //FIXME: Make 60 an .ini setting |
388 | if (Environment.TickCount - client.TickLastPacketReceived > 1000 * 60) | 381 | if (Environment.TickCount - client.TickLastPacketReceived > 1000 * 60) |
389 | { | 382 | { |
390 | m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + client.RemoteEndPoint); | 383 | m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + client.ClientAPI.Name); |
391 | 384 | ||
392 | RemoveClient(client); | 385 | RemoveClient(client.ClientAPI); |
393 | return; | 386 | return; |
394 | } | 387 | } |
395 | } | 388 | } |
@@ -590,8 +583,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
590 | LLUDPClient client = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint); | 583 | LLUDPClient client = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint); |
591 | clients.Add(agentID, client.RemoteEndPoint, client); | 584 | clients.Add(agentID, client.RemoteEndPoint, client); |
592 | 585 | ||
593 | // Create the IClientAPI | 586 | // Create the LLClientView |
594 | IClientAPI clientApi = new LLClientView(remoteEndPoint, m_scene, this, client, sessionInfo, agentID, sessionID, circuitCode); | 587 | LLClientView clientApi = new LLClientView(remoteEndPoint, m_scene, this, client, sessionInfo, agentID, sessionID, circuitCode); |
595 | clientApi.OnViewerEffect += m_scene.ClientManager.ViewerEffectHandler; | 588 | clientApi.OnViewerEffect += m_scene.ClientManager.ViewerEffectHandler; |
596 | clientApi.OnLogout += LogoutHandler; | 589 | clientApi.OnLogout += LogoutHandler; |
597 | clientApi.OnConnectionClosed += RemoveClient; | 590 | clientApi.OnConnectionClosed += RemoveClient; |
@@ -618,23 +611,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
618 | 611 | ||
619 | private void IncomingPacketHandler() | 612 | private void IncomingPacketHandler() |
620 | { | 613 | { |
621 | IncomingPacket incomingPacket = new IncomingPacket(); | 614 | // Set this culture for the thread that incoming packets are received |
622 | Packet packet = null; | 615 | // on to en-US to avoid number parsing issues |
623 | LLUDPClient client = null; | 616 | Culture.SetCurrentCulture(); |
617 | |||
618 | IncomingPacket incomingPacket = default(IncomingPacket); | ||
624 | 619 | ||
625 | while (base.IsRunning) | 620 | while (base.IsRunning) |
626 | { | 621 | { |
627 | // Reset packet to null for the check below | ||
628 | packet = null; | ||
629 | |||
630 | if (packetInbox.Dequeue(100, ref incomingPacket)) | 622 | if (packetInbox.Dequeue(100, ref incomingPacket)) |
631 | { | 623 | Util.FireAndForget(ProcessInPacket, incomingPacket); |
632 | packet = incomingPacket.Packet; | ||
633 | client = incomingPacket.Client; | ||
634 | |||
635 | if (packet != null && client != null) | ||
636 | client.ClientAPI.ProcessInPacket(packet); | ||
637 | } | ||
638 | } | 624 | } |
639 | 625 | ||
640 | if (packetInbox.Count > 0) | 626 | if (packetInbox.Count > 0) |
@@ -642,32 +628,98 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
642 | packetInbox.Clear(); | 628 | packetInbox.Clear(); |
643 | } | 629 | } |
644 | 630 | ||
631 | private void ProcessInPacket(object state) | ||
632 | { | ||
633 | IncomingPacket incomingPacket = (IncomingPacket)state; | ||
634 | Packet packet = incomingPacket.Packet; | ||
635 | LLUDPClient client = incomingPacket.Client; | ||
636 | |||
637 | if (packet != null && client != null) | ||
638 | { | ||
639 | try | ||
640 | { | ||
641 | client.ClientAPI.ProcessInPacket(packet); | ||
642 | } | ||
643 | catch (ThreadAbortException) | ||
644 | { | ||
645 | throw; | ||
646 | } | ||
647 | catch (Exception e) | ||
648 | { | ||
649 | if (StatsManager.SimExtraStats != null) | ||
650 | StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); | ||
651 | |||
652 | // Don't let a failure in an individual client thread crash the whole sim. | ||
653 | m_log.ErrorFormat("[LLUDPSERVER]: Client thread for {0} {1} crashed. Logging them out", client.ClientAPI.Name, client.AgentID); | ||
654 | m_log.Error(e.Message, e); | ||
655 | |||
656 | try | ||
657 | { | ||
658 | // Make an attempt to alert the user that their session has crashed | ||
659 | AgentAlertMessagePacket alert = client.ClientAPI.BuildAgentAlertPacket( | ||
660 | "Unfortunately the session for this client on the server has crashed.\n" + | ||
661 | "Any further actions taken will not be processed.\n" + | ||
662 | "Please relog", true); | ||
663 | |||
664 | SendPacket(client, alert, ThrottleOutPacketType.Unknown, false); | ||
665 | |||
666 | // TODO: There may be a better way to do this. Perhaps kick? Not sure this propogates notifications to | ||
667 | // listeners yet, though. | ||
668 | client.ClientAPI.SendLogoutPacket(); | ||
669 | RemoveClient(client.ClientAPI); | ||
670 | } | ||
671 | catch (ThreadAbortException) | ||
672 | { | ||
673 | throw; | ||
674 | } | ||
675 | catch (Exception e2) | ||
676 | { | ||
677 | m_log.Error("[LLUDPSERVER]: Further exception thrown on forced session logout for " + client.ClientAPI.Name); | ||
678 | m_log.Error(e2.Message, e2); | ||
679 | } | ||
680 | } | ||
681 | } | ||
682 | } | ||
683 | |||
645 | private void OutgoingPacketHandler() | 684 | private void OutgoingPacketHandler() |
646 | { | 685 | { |
686 | // Set this culture for the thread that outgoing packets are sent | ||
687 | // on to en-US to avoid number parsing issues | ||
688 | Culture.SetCurrentCulture(); | ||
689 | |||
647 | int now = Environment.TickCount; | 690 | int now = Environment.TickCount; |
648 | int elapsedMS = 0; | 691 | int elapsedMS = 0; |
649 | int elapsed100MS = 0; | 692 | int elapsed100MS = 0; |
693 | int elapsed500MS = 0; | ||
650 | 694 | ||
651 | while (base.IsRunning) | 695 | while (base.IsRunning) |
652 | { | 696 | { |
653 | bool resendUnacked = false; | 697 | bool resendUnacked = false; |
654 | bool sendAcks = false; | 698 | bool sendAcks = false; |
699 | bool sendPings = false; | ||
655 | bool packetSent = false; | 700 | bool packetSent = false; |
656 | 701 | ||
657 | elapsedMS += Environment.TickCount - now; | 702 | elapsedMS += Environment.TickCount - now; |
658 | 703 | ||
659 | // Check for packets that need to be resent every 100ms | 704 | // Check for pending outgoing resends every 100ms |
660 | if (elapsedMS >= 100) | 705 | if (elapsedMS >= 100) |
661 | { | 706 | { |
662 | resendUnacked = true; | 707 | resendUnacked = true; |
663 | elapsedMS -= 100; | 708 | elapsedMS -= 100; |
664 | ++elapsed100MS; | 709 | ++elapsed100MS; |
665 | } | 710 | } |
666 | // Check for ACKs that need to be sent out every 500ms | 711 | // Check for pending outgoing ACKs every 500ms |
667 | if (elapsed100MS >= 5) | 712 | if (elapsed100MS >= 5) |
668 | { | 713 | { |
669 | sendAcks = true; | 714 | sendAcks = true; |
670 | elapsed100MS = 0; | 715 | elapsed100MS = 0; |
716 | ++elapsed500MS; | ||
717 | } | ||
718 | // Send pings to clients every 2000ms | ||
719 | if (elapsed500MS >= 4) | ||
720 | { | ||
721 | sendPings = true; | ||
722 | elapsed500MS = 0; | ||
671 | } | 723 | } |
672 | 724 | ||
673 | clients.ForEach( | 725 | clients.ForEach( |
@@ -679,6 +731,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
679 | ResendUnacked(client); | 731 | ResendUnacked(client); |
680 | if (sendAcks) | 732 | if (sendAcks) |
681 | SendAcks(client); | 733 | SendAcks(client); |
734 | if (sendPings) | ||
735 | SendPing(client); | ||
682 | } | 736 | } |
683 | ); | 737 | ); |
684 | 738 | ||