diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 218 |
1 files changed, 197 insertions, 21 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index d11fcbf..b3db064 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -110,7 +110,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
110 | /// <summary>Handlers for incoming packets</summary> | 110 | /// <summary>Handlers for incoming packets</summary> |
111 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); | 111 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); |
112 | /// <summary>Incoming packets that are awaiting handling</summary> | 112 | /// <summary>Incoming packets that are awaiting handling</summary> |
113 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); | 113 | //private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); |
114 | |||
115 | private DoubleQueue<IncomingPacket> packetInbox = new DoubleQueue<IncomingPacket>(); | ||
116 | |||
114 | /// <summary></summary> | 117 | /// <summary></summary> |
115 | //private UDPClientCollection m_clients = new UDPClientCollection(); | 118 | //private UDPClientCollection m_clients = new UDPClientCollection(); |
116 | /// <summary>Bandwidth throttle for this UDP server</summary> | 119 | /// <summary>Bandwidth throttle for this UDP server</summary> |
@@ -155,6 +158,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
155 | /// <summary>Flag to signal when clients should send pings</summary> | 158 | /// <summary>Flag to signal when clients should send pings</summary> |
156 | protected bool m_sendPing; | 159 | protected bool m_sendPing; |
157 | 160 | ||
161 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); | ||
162 | |||
158 | private int m_defaultRTO = 0; | 163 | private int m_defaultRTO = 0; |
159 | private int m_maxRTO = 0; | 164 | private int m_maxRTO = 0; |
160 | private int m_ackTimeout = 0; | 165 | private int m_ackTimeout = 0; |
@@ -774,19 +779,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
774 | 779 | ||
775 | #region Packet to Client Mapping | 780 | #region Packet to Client Mapping |
776 | 781 | ||
777 | // UseCircuitCode handling | 782 | // If there is already a client for this endpoint, don't process UseCircuitCode |
778 | if (packet.Type == PacketType.UseCircuitCode) | 783 | IClientAPI client = null; |
784 | if (!m_scene.TryGetClient(address, out client)) | ||
779 | { | 785 | { |
780 | object[] array = new object[] { buffer, packet }; | 786 | // UseCircuitCode handling |
787 | if (packet.Type == PacketType.UseCircuitCode) | ||
788 | { | ||
789 | // And if there is a UseCircuitCode pending, also drop it | ||
790 | lock (m_pendingCache) | ||
791 | { | ||
792 | if (m_pendingCache.Contains(address)) | ||
793 | return; | ||
781 | 794 | ||
782 | Util.FireAndForget(HandleUseCircuitCode, array); | 795 | m_pendingCache.AddOrUpdate(address, new Queue<UDPPacketBuffer>(), 60); |
796 | } | ||
783 | 797 | ||
784 | return; | 798 | object[] array = new object[] { buffer, packet }; |
799 | |||
800 | Util.FireAndForget(HandleUseCircuitCode, array); | ||
801 | |||
802 | return; | ||
803 | } | ||
804 | } | ||
805 | |||
806 | // If this is a pending connection, enqueue, don't process yet | ||
807 | lock (m_pendingCache) | ||
808 | { | ||
809 | Queue<UDPPacketBuffer> queue; | ||
810 | if (m_pendingCache.TryGetValue(address, out queue)) | ||
811 | { | ||
812 | //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); | ||
813 | queue.Enqueue(buffer); | ||
814 | return; | ||
815 | } | ||
785 | } | 816 | } |
786 | 817 | ||
787 | // Determine which agent this packet came from | 818 | // Determine which agent this packet came from |
788 | IClientAPI client; | 819 | if (client == null || !(client is LLClientView)) |
789 | if (!m_scene.TryGetClient(address, out client) || !(client is LLClientView)) | ||
790 | { | 820 | { |
791 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 821 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
792 | return; | 822 | return; |
@@ -795,7 +825,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
795 | udpClient = ((LLClientView)client).UDPClient; | 825 | udpClient = ((LLClientView)client).UDPClient; |
796 | 826 | ||
797 | if (!udpClient.IsConnected) | 827 | if (!udpClient.IsConnected) |
828 | { | ||
829 | // m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName); | ||
798 | return; | 830 | return; |
831 | } | ||
799 | 832 | ||
800 | #endregion Packet to Client Mapping | 833 | #endregion Packet to Client Mapping |
801 | 834 | ||
@@ -898,7 +931,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
898 | #endregion Ping Check Handling | 931 | #endregion Ping Check Handling |
899 | 932 | ||
900 | // Inbox insertion | 933 | // Inbox insertion |
901 | packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet)); | 934 | if (packet.Type == PacketType.AgentUpdate || |
935 | packet.Type == PacketType.ChatFromViewer) | ||
936 | packetInbox.EnqueueHigh(new IncomingPacket((LLClientView)client, packet)); | ||
937 | else | ||
938 | packetInbox.EnqueueLow(new IncomingPacket((LLClientView)client, packet)); | ||
939 | // packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet)); | ||
902 | } | 940 | } |
903 | 941 | ||
904 | #region BinaryStats | 942 | #region BinaryStats |
@@ -1020,6 +1058,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1020 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | 1058 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1021 | if (client != null) | 1059 | if (client != null) |
1022 | client.SceneAgent.SendInitialDataToMe(); | 1060 | client.SceneAgent.SendInitialDataToMe(); |
1061 | |||
1062 | // Now we know we can handle more data | ||
1063 | Thread.Sleep(200); | ||
1064 | |||
1065 | // Obtain the queue and remove it from the cache | ||
1066 | Queue<UDPPacketBuffer> queue = null; | ||
1067 | |||
1068 | lock (m_pendingCache) | ||
1069 | { | ||
1070 | if (!m_pendingCache.TryGetValue(remoteEndPoint, out queue)) | ||
1071 | { | ||
1072 | m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); | ||
1073 | return; | ||
1074 | } | ||
1075 | m_pendingCache.Remove(remoteEndPoint); | ||
1076 | } | ||
1077 | |||
1078 | m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); | ||
1079 | |||
1080 | // Reinject queued packets | ||
1081 | while(queue.Count > 0) | ||
1082 | { | ||
1083 | UDPPacketBuffer buf = queue.Dequeue(); | ||
1084 | PacketReceived(buf); | ||
1085 | } | ||
1086 | queue = null; | ||
1023 | } | 1087 | } |
1024 | else | 1088 | else |
1025 | { | 1089 | { |
@@ -1027,6 +1091,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1027 | m_log.WarnFormat( | 1091 | m_log.WarnFormat( |
1028 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", | 1092 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", |
1029 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); | 1093 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); |
1094 | lock (m_pendingCache) | ||
1095 | m_pendingCache.Remove(remoteEndPoint); | ||
1030 | } | 1096 | } |
1031 | 1097 | ||
1032 | // m_log.DebugFormat( | 1098 | // m_log.DebugFormat( |
@@ -1145,7 +1211,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1145 | if (!client.SceneAgent.IsChildAgent) | 1211 | if (!client.SceneAgent.IsChildAgent) |
1146 | client.Kick("Simulator logged you out due to connection timeout"); | 1212 | client.Kick("Simulator logged you out due to connection timeout"); |
1147 | 1213 | ||
1148 | client.CloseWithoutChecks(); | 1214 | client.CloseWithoutChecks(true); |
1149 | } | 1215 | } |
1150 | } | 1216 | } |
1151 | 1217 | ||
@@ -1157,6 +1223,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1157 | 1223 | ||
1158 | while (base.IsRunning) | 1224 | while (base.IsRunning) |
1159 | { | 1225 | { |
1226 | m_scene.ThreadAlive(1); | ||
1160 | try | 1227 | try |
1161 | { | 1228 | { |
1162 | IncomingPacket incomingPacket = null; | 1229 | IncomingPacket incomingPacket = null; |
@@ -1199,6 +1266,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1199 | 1266 | ||
1200 | while (base.IsRunning) | 1267 | while (base.IsRunning) |
1201 | { | 1268 | { |
1269 | m_scene.ThreadAlive(2); | ||
1202 | try | 1270 | try |
1203 | { | 1271 | { |
1204 | m_packetSent = false; | 1272 | m_packetSent = false; |
@@ -1420,8 +1488,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1420 | Packet packet = incomingPacket.Packet; | 1488 | Packet packet = incomingPacket.Packet; |
1421 | LLClientView client = incomingPacket.Client; | 1489 | LLClientView client = incomingPacket.Client; |
1422 | 1490 | ||
1423 | if (client.IsActive) | 1491 | // if (client.IsActive) |
1424 | { | 1492 | // { |
1425 | m_currentIncomingClient = client; | 1493 | m_currentIncomingClient = client; |
1426 | 1494 | ||
1427 | try | 1495 | try |
@@ -1448,13 +1516,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1448 | { | 1516 | { |
1449 | m_currentIncomingClient = null; | 1517 | m_currentIncomingClient = null; |
1450 | } | 1518 | } |
1451 | } | 1519 | // } |
1452 | else | 1520 | // else |
1453 | { | 1521 | // { |
1454 | m_log.DebugFormat( | 1522 | // m_log.DebugFormat( |
1455 | "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", | 1523 | // "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", |
1456 | packet.Type, client.Name, m_scene.RegionInfo.RegionName); | 1524 | // packet.Type, client.Name, m_scene.RegionInfo.RegionName); |
1457 | } | 1525 | // } |
1458 | } | 1526 | } |
1459 | 1527 | ||
1460 | protected void LogoutHandler(IClientAPI client) | 1528 | protected void LogoutHandler(IClientAPI client) |
@@ -1464,8 +1532,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1464 | if (!client.IsLoggingOut) | 1532 | if (!client.IsLoggingOut) |
1465 | { | 1533 | { |
1466 | client.IsLoggingOut = true; | 1534 | client.IsLoggingOut = true; |
1467 | client.Close(); | 1535 | client.Close(false, false); |
1536 | } | ||
1537 | } | ||
1538 | } | ||
1539 | |||
1540 | internal class DoubleQueue<T> where T:class | ||
1541 | { | ||
1542 | private Queue<T> m_lowQueue = new Queue<T>(); | ||
1543 | private Queue<T> m_highQueue = new Queue<T>(); | ||
1544 | |||
1545 | private object m_syncRoot = new object(); | ||
1546 | private Semaphore m_s = new Semaphore(0, 1); | ||
1547 | |||
1548 | public DoubleQueue() | ||
1549 | { | ||
1550 | } | ||
1551 | |||
1552 | public virtual int Count | ||
1553 | { | ||
1554 | get { return m_highQueue.Count + m_lowQueue.Count; } | ||
1555 | } | ||
1556 | |||
1557 | public virtual void Enqueue(T data) | ||
1558 | { | ||
1559 | Enqueue(m_lowQueue, data); | ||
1560 | } | ||
1561 | |||
1562 | public virtual void EnqueueLow(T data) | ||
1563 | { | ||
1564 | Enqueue(m_lowQueue, data); | ||
1565 | } | ||
1566 | |||
1567 | public virtual void EnqueueHigh(T data) | ||
1568 | { | ||
1569 | Enqueue(m_highQueue, data); | ||
1570 | } | ||
1571 | |||
1572 | private void Enqueue(Queue<T> q, T data) | ||
1573 | { | ||
1574 | lock (m_syncRoot) | ||
1575 | { | ||
1576 | m_lowQueue.Enqueue(data); | ||
1577 | m_s.WaitOne(0); | ||
1578 | m_s.Release(); | ||
1579 | } | ||
1580 | } | ||
1581 | |||
1582 | public virtual T Dequeue() | ||
1583 | { | ||
1584 | return Dequeue(Timeout.Infinite); | ||
1585 | } | ||
1586 | |||
1587 | public virtual T Dequeue(int tmo) | ||
1588 | { | ||
1589 | return Dequeue(TimeSpan.FromMilliseconds(tmo)); | ||
1590 | } | ||
1591 | |||
1592 | public virtual T Dequeue(TimeSpan wait) | ||
1593 | { | ||
1594 | T res = null; | ||
1595 | |||
1596 | if (!Dequeue(wait, ref res)) | ||
1597 | return null; | ||
1598 | |||
1599 | return res; | ||
1600 | } | ||
1601 | |||
1602 | public bool Dequeue(int timeout, ref T res) | ||
1603 | { | ||
1604 | return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res); | ||
1605 | } | ||
1606 | |||
1607 | public bool Dequeue(TimeSpan wait, ref T res) | ||
1608 | { | ||
1609 | if (!m_s.WaitOne(wait)) | ||
1610 | return false; | ||
1611 | |||
1612 | lock (m_syncRoot) | ||
1613 | { | ||
1614 | if (m_highQueue.Count > 0) | ||
1615 | res = m_highQueue.Dequeue(); | ||
1616 | else | ||
1617 | res = m_lowQueue.Dequeue(); | ||
1618 | |||
1619 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) | ||
1620 | return true; | ||
1621 | |||
1622 | try | ||
1623 | { | ||
1624 | m_s.Release(); | ||
1625 | } | ||
1626 | catch | ||
1627 | { | ||
1628 | } | ||
1629 | |||
1630 | return true; | ||
1631 | } | ||
1632 | } | ||
1633 | |||
1634 | public virtual void Clear() | ||
1635 | { | ||
1636 | |||
1637 | lock (m_syncRoot) | ||
1638 | { | ||
1639 | // Make sure sem count is 0 | ||
1640 | m_s.WaitOne(0); | ||
1641 | |||
1642 | m_lowQueue.Clear(); | ||
1643 | m_highQueue.Clear(); | ||
1468 | } | 1644 | } |
1469 | } | 1645 | } |
1470 | } | 1646 | } |
1471 | } \ No newline at end of file | 1647 | } |