diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 219 |
1 files changed, 196 insertions, 23 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 14cc863..b8951d9 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -113,7 +113,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
113 | /// <summary>Handlers for incoming packets</summary> | 113 | /// <summary>Handlers for incoming packets</summary> |
114 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); | 114 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); |
115 | /// <summary>Incoming packets that are awaiting handling</summary> | 115 | /// <summary>Incoming packets that are awaiting handling</summary> |
116 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); | 116 | //private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); |
117 | |||
118 | private DoubleQueue<IncomingPacket> packetInbox = new DoubleQueue<IncomingPacket>(); | ||
117 | 119 | ||
118 | /// <summary></summary> | 120 | /// <summary></summary> |
119 | //private UDPClientCollection m_clients = new UDPClientCollection(); | 121 | //private UDPClientCollection m_clients = new UDPClientCollection(); |
@@ -168,6 +170,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
168 | /// <summary>Flag to signal when clients should send pings</summary> | 170 | /// <summary>Flag to signal when clients should send pings</summary> |
169 | protected bool m_sendPing; | 171 | protected bool m_sendPing; |
170 | 172 | ||
173 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); | ||
171 | private Pool<IncomingPacket> m_incomingPacketPool; | 174 | private Pool<IncomingPacket> m_incomingPacketPool; |
172 | 175 | ||
173 | private Stat m_incomingPacketPoolStat; | 176 | private Stat m_incomingPacketPoolStat; |
@@ -974,21 +977,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
974 | 977 | ||
975 | #region Packet to Client Mapping | 978 | #region Packet to Client Mapping |
976 | 979 | ||
977 | // UseCircuitCode handling | 980 | // If there is already a client for this endpoint, don't process UseCircuitCode |
978 | if (packet.Type == PacketType.UseCircuitCode) | 981 | IClientAPI client = null; |
982 | if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) | ||
979 | { | 983 | { |
980 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the | 984 | // UseCircuitCode handling |
981 | // buffer. | 985 | if (packet.Type == PacketType.UseCircuitCode) |
982 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | 986 | { |
987 | // And if there is a UseCircuitCode pending, also drop it | ||
988 | lock (m_pendingCache) | ||
989 | { | ||
990 | if (m_pendingCache.Contains(endPoint)) | ||
991 | return; | ||
983 | 992 | ||
984 | Util.FireAndForget(HandleUseCircuitCode, array); | 993 | m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60); |
994 | } | ||
985 | 995 | ||
986 | return; | 996 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the |
997 | // buffer. | ||
998 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | ||
999 | |||
1000 | Util.FireAndForget(HandleUseCircuitCode, array); | ||
1001 | |||
1002 | return; | ||
1003 | } | ||
1004 | } | ||
1005 | |||
1006 | // If this is a pending connection, enqueue, don't process yet | ||
1007 | lock (m_pendingCache) | ||
1008 | { | ||
1009 | Queue<UDPPacketBuffer> queue; | ||
1010 | if (m_pendingCache.TryGetValue(endPoint, out queue)) | ||
1011 | { | ||
1012 | //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); | ||
1013 | queue.Enqueue(buffer); | ||
1014 | return; | ||
1015 | } | ||
987 | } | 1016 | } |
988 | 1017 | ||
989 | // Determine which agent this packet came from | 1018 | // Determine which agent this packet came from |
990 | IClientAPI client; | 1019 | if (client == null || !(client is LLClientView)) |
991 | if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) | ||
992 | { | 1020 | { |
993 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 1021 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
994 | return; | 1022 | return; |
@@ -997,7 +1025,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
997 | udpClient = ((LLClientView)client).UDPClient; | 1025 | udpClient = ((LLClientView)client).UDPClient; |
998 | 1026 | ||
999 | if (!udpClient.IsConnected) | 1027 | if (!udpClient.IsConnected) |
1028 | { | ||
1029 | // m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName); | ||
1000 | return; | 1030 | return; |
1031 | } | ||
1001 | 1032 | ||
1002 | #endregion Packet to Client Mapping | 1033 | #endregion Packet to Client Mapping |
1003 | 1034 | ||
@@ -1127,7 +1158,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1127 | incomingPacket = new IncomingPacket((LLClientView)client, packet); | 1158 | incomingPacket = new IncomingPacket((LLClientView)client, packet); |
1128 | } | 1159 | } |
1129 | 1160 | ||
1130 | packetInbox.Enqueue(incomingPacket); | 1161 | if (incomingPacket.Packet.Type == PacketType.AgentUpdate || |
1162 | incomingPacket.Packet.Type == PacketType.ChatFromViewer) | ||
1163 | packetInbox.EnqueueHigh(incomingPacket); | ||
1164 | else | ||
1165 | packetInbox.EnqueueLow(incomingPacket); | ||
1131 | } | 1166 | } |
1132 | 1167 | ||
1133 | #region BinaryStats | 1168 | #region BinaryStats |
@@ -1247,6 +1282,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1247 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | 1282 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1248 | if (client != null) | 1283 | if (client != null) |
1249 | client.SceneAgent.SendInitialDataToMe(); | 1284 | client.SceneAgent.SendInitialDataToMe(); |
1285 | |||
1286 | // Now we know we can handle more data | ||
1287 | Thread.Sleep(200); | ||
1288 | |||
1289 | // Obtain the queue and remove it from the cache | ||
1290 | Queue<UDPPacketBuffer> queue = null; | ||
1291 | |||
1292 | lock (m_pendingCache) | ||
1293 | { | ||
1294 | if (!m_pendingCache.TryGetValue(endPoint, out queue)) | ||
1295 | { | ||
1296 | m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); | ||
1297 | return; | ||
1298 | } | ||
1299 | m_pendingCache.Remove(endPoint); | ||
1300 | } | ||
1301 | |||
1302 | m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); | ||
1303 | |||
1304 | // Reinject queued packets | ||
1305 | while(queue.Count > 0) | ||
1306 | { | ||
1307 | UDPPacketBuffer buf = queue.Dequeue(); | ||
1308 | PacketReceived(buf); | ||
1309 | } | ||
1310 | queue = null; | ||
1250 | } | 1311 | } |
1251 | else | 1312 | else |
1252 | { | 1313 | { |
@@ -1254,6 +1315,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1254 | m_log.WarnFormat( | 1315 | m_log.WarnFormat( |
1255 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", | 1316 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", |
1256 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); | 1317 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); |
1318 | lock (m_pendingCache) | ||
1319 | m_pendingCache.Remove(endPoint); | ||
1257 | } | 1320 | } |
1258 | 1321 | ||
1259 | // m_log.DebugFormat( | 1322 | // m_log.DebugFormat( |
@@ -1372,7 +1435,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1372 | if (!client.SceneAgent.IsChildAgent) | 1435 | if (!client.SceneAgent.IsChildAgent) |
1373 | client.Kick("Simulator logged you out due to connection timeout"); | 1436 | client.Kick("Simulator logged you out due to connection timeout"); |
1374 | 1437 | ||
1375 | client.CloseWithoutChecks(); | 1438 | client.CloseWithoutChecks(true); |
1376 | } | 1439 | } |
1377 | } | 1440 | } |
1378 | 1441 | ||
@@ -1384,6 +1447,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1384 | 1447 | ||
1385 | while (IsRunningInbound) | 1448 | while (IsRunningInbound) |
1386 | { | 1449 | { |
1450 | m_scene.ThreadAlive(1); | ||
1387 | try | 1451 | try |
1388 | { | 1452 | { |
1389 | IncomingPacket incomingPacket = null; | 1453 | IncomingPacket incomingPacket = null; |
@@ -1431,6 +1495,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1431 | 1495 | ||
1432 | while (base.IsRunningOutbound) | 1496 | while (base.IsRunningOutbound) |
1433 | { | 1497 | { |
1498 | m_scene.ThreadAlive(2); | ||
1434 | try | 1499 | try |
1435 | { | 1500 | { |
1436 | m_packetSent = false; | 1501 | m_packetSent = false; |
@@ -1652,8 +1717,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1652 | Packet packet = incomingPacket.Packet; | 1717 | Packet packet = incomingPacket.Packet; |
1653 | LLClientView client = incomingPacket.Client; | 1718 | LLClientView client = incomingPacket.Client; |
1654 | 1719 | ||
1655 | if (client.IsActive) | 1720 | // if (client.IsActive) |
1656 | { | 1721 | // { |
1657 | m_currentIncomingClient = client; | 1722 | m_currentIncomingClient = client; |
1658 | 1723 | ||
1659 | try | 1724 | try |
@@ -1680,13 +1745,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1680 | { | 1745 | { |
1681 | m_currentIncomingClient = null; | 1746 | m_currentIncomingClient = null; |
1682 | } | 1747 | } |
1683 | } | 1748 | // } |
1684 | else | 1749 | // else |
1685 | { | 1750 | // { |
1686 | m_log.DebugFormat( | 1751 | // m_log.DebugFormat( |
1687 | "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", | 1752 | // "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", |
1688 | packet.Type, client.Name, m_scene.RegionInfo.RegionName); | 1753 | // packet.Type, client.Name, m_scene.RegionInfo.RegionName); |
1689 | } | 1754 | // } |
1690 | } | 1755 | } |
1691 | 1756 | ||
1692 | protected void LogoutHandler(IClientAPI client) | 1757 | protected void LogoutHandler(IClientAPI client) |
@@ -1696,8 +1761,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1696 | if (!client.IsLoggingOut) | 1761 | if (!client.IsLoggingOut) |
1697 | { | 1762 | { |
1698 | client.IsLoggingOut = true; | 1763 | client.IsLoggingOut = true; |
1699 | client.Close(); | 1764 | client.Close(false, false); |
1765 | } | ||
1766 | } | ||
1767 | } | ||
1768 | |||
1769 | internal class DoubleQueue<T> where T:class | ||
1770 | { | ||
1771 | private Queue<T> m_lowQueue = new Queue<T>(); | ||
1772 | private Queue<T> m_highQueue = new Queue<T>(); | ||
1773 | |||
1774 | private object m_syncRoot = new object(); | ||
1775 | private Semaphore m_s = new Semaphore(0, 1); | ||
1776 | |||
1777 | public DoubleQueue() | ||
1778 | { | ||
1779 | } | ||
1780 | |||
1781 | public virtual int Count | ||
1782 | { | ||
1783 | get { return m_highQueue.Count + m_lowQueue.Count; } | ||
1784 | } | ||
1785 | |||
1786 | public virtual void Enqueue(T data) | ||
1787 | { | ||
1788 | Enqueue(m_lowQueue, data); | ||
1789 | } | ||
1790 | |||
1791 | public virtual void EnqueueLow(T data) | ||
1792 | { | ||
1793 | Enqueue(m_lowQueue, data); | ||
1794 | } | ||
1795 | |||
1796 | public virtual void EnqueueHigh(T data) | ||
1797 | { | ||
1798 | Enqueue(m_highQueue, data); | ||
1799 | } | ||
1800 | |||
1801 | private void Enqueue(Queue<T> q, T data) | ||
1802 | { | ||
1803 | lock (m_syncRoot) | ||
1804 | { | ||
1805 | m_lowQueue.Enqueue(data); | ||
1806 | m_s.WaitOne(0); | ||
1807 | m_s.Release(); | ||
1808 | } | ||
1809 | } | ||
1810 | |||
1811 | public virtual T Dequeue() | ||
1812 | { | ||
1813 | return Dequeue(Timeout.Infinite); | ||
1814 | } | ||
1815 | |||
1816 | public virtual T Dequeue(int tmo) | ||
1817 | { | ||
1818 | return Dequeue(TimeSpan.FromMilliseconds(tmo)); | ||
1819 | } | ||
1820 | |||
1821 | public virtual T Dequeue(TimeSpan wait) | ||
1822 | { | ||
1823 | T res = null; | ||
1824 | |||
1825 | if (!Dequeue(wait, ref res)) | ||
1826 | return null; | ||
1827 | |||
1828 | return res; | ||
1829 | } | ||
1830 | |||
1831 | public bool Dequeue(int timeout, ref T res) | ||
1832 | { | ||
1833 | return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res); | ||
1834 | } | ||
1835 | |||
1836 | public bool Dequeue(TimeSpan wait, ref T res) | ||
1837 | { | ||
1838 | if (!m_s.WaitOne(wait)) | ||
1839 | return false; | ||
1840 | |||
1841 | lock (m_syncRoot) | ||
1842 | { | ||
1843 | if (m_highQueue.Count > 0) | ||
1844 | res = m_highQueue.Dequeue(); | ||
1845 | else | ||
1846 | res = m_lowQueue.Dequeue(); | ||
1847 | |||
1848 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) | ||
1849 | return true; | ||
1850 | |||
1851 | try | ||
1852 | { | ||
1853 | m_s.Release(); | ||
1854 | } | ||
1855 | catch | ||
1856 | { | ||
1857 | } | ||
1858 | |||
1859 | return true; | ||
1860 | } | ||
1861 | } | ||
1862 | |||
1863 | public virtual void Clear() | ||
1864 | { | ||
1865 | |||
1866 | lock (m_syncRoot) | ||
1867 | { | ||
1868 | // Make sure sem count is 0 | ||
1869 | m_s.WaitOne(0); | ||
1870 | |||
1871 | m_lowQueue.Clear(); | ||
1872 | m_highQueue.Clear(); | ||
1700 | } | 1873 | } |
1701 | } | 1874 | } |
1702 | } | 1875 | } |
1703 | } \ No newline at end of file | 1876 | } |