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 a7628d2..9a4abd4 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -126,7 +126,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
126 | /// <summary>Handlers for incoming packets</summary> | 126 | /// <summary>Handlers for incoming packets</summary> |
127 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); | 127 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); |
128 | /// <summary>Incoming packets that are awaiting handling</summary> | 128 | /// <summary>Incoming packets that are awaiting handling</summary> |
129 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); | 129 | //private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); |
130 | |||
131 | private DoubleQueue<IncomingPacket> packetInbox = new DoubleQueue<IncomingPacket>(); | ||
130 | 132 | ||
131 | /// <summary></summary> | 133 | /// <summary></summary> |
132 | //private UDPClientCollection m_clients = new UDPClientCollection(); | 134 | //private UDPClientCollection m_clients = new UDPClientCollection(); |
@@ -181,6 +183,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
181 | /// <summary>Flag to signal when clients should send pings</summary> | 183 | /// <summary>Flag to signal when clients should send pings</summary> |
182 | protected bool m_sendPing; | 184 | protected bool m_sendPing; |
183 | 185 | ||
186 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); | ||
184 | private Pool<IncomingPacket> m_incomingPacketPool; | 187 | private Pool<IncomingPacket> m_incomingPacketPool; |
185 | 188 | ||
186 | /// <summary> | 189 | /// <summary> |
@@ -1093,21 +1096,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1093 | 1096 | ||
1094 | #region Packet to Client Mapping | 1097 | #region Packet to Client Mapping |
1095 | 1098 | ||
1096 | // UseCircuitCode handling | 1099 | // If there is already a client for this endpoint, don't process UseCircuitCode |
1097 | if (packet.Type == PacketType.UseCircuitCode) | 1100 | IClientAPI client = null; |
1101 | if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) | ||
1098 | { | 1102 | { |
1099 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the | 1103 | // UseCircuitCode handling |
1100 | // buffer. | 1104 | if (packet.Type == PacketType.UseCircuitCode) |
1101 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | 1105 | { |
1106 | // And if there is a UseCircuitCode pending, also drop it | ||
1107 | lock (m_pendingCache) | ||
1108 | { | ||
1109 | if (m_pendingCache.Contains(endPoint)) | ||
1110 | return; | ||
1102 | 1111 | ||
1103 | Util.FireAndForget(HandleUseCircuitCode, array); | 1112 | m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60); |
1113 | } | ||
1104 | 1114 | ||
1105 | return; | 1115 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the |
1116 | // buffer. | ||
1117 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | ||
1118 | |||
1119 | Util.FireAndForget(HandleUseCircuitCode, array); | ||
1120 | |||
1121 | return; | ||
1122 | } | ||
1123 | } | ||
1124 | |||
1125 | // If this is a pending connection, enqueue, don't process yet | ||
1126 | lock (m_pendingCache) | ||
1127 | { | ||
1128 | Queue<UDPPacketBuffer> queue; | ||
1129 | if (m_pendingCache.TryGetValue(endPoint, out queue)) | ||
1130 | { | ||
1131 | //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); | ||
1132 | queue.Enqueue(buffer); | ||
1133 | return; | ||
1134 | } | ||
1106 | } | 1135 | } |
1107 | 1136 | ||
1108 | // Determine which agent this packet came from | 1137 | // Determine which agent this packet came from |
1109 | IClientAPI client; | 1138 | if (client == null || !(client is LLClientView)) |
1110 | if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) | ||
1111 | { | 1139 | { |
1112 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 1140 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
1113 | return; | 1141 | return; |
@@ -1116,7 +1144,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1116 | udpClient = ((LLClientView)client).UDPClient; | 1144 | udpClient = ((LLClientView)client).UDPClient; |
1117 | 1145 | ||
1118 | if (!udpClient.IsConnected) | 1146 | if (!udpClient.IsConnected) |
1147 | { | ||
1148 | // m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName); | ||
1119 | return; | 1149 | return; |
1150 | } | ||
1120 | 1151 | ||
1121 | #endregion Packet to Client Mapping | 1152 | #endregion Packet to Client Mapping |
1122 | 1153 | ||
@@ -1246,7 +1277,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1246 | incomingPacket = new IncomingPacket((LLClientView)client, packet); | 1277 | incomingPacket = new IncomingPacket((LLClientView)client, packet); |
1247 | } | 1278 | } |
1248 | 1279 | ||
1249 | packetInbox.Enqueue(incomingPacket); | 1280 | if (incomingPacket.Packet.Type == PacketType.AgentUpdate || |
1281 | incomingPacket.Packet.Type == PacketType.ChatFromViewer) | ||
1282 | packetInbox.EnqueueHigh(incomingPacket); | ||
1283 | else | ||
1284 | packetInbox.EnqueueLow(incomingPacket); | ||
1250 | } | 1285 | } |
1251 | 1286 | ||
1252 | #region BinaryStats | 1287 | #region BinaryStats |
@@ -1366,6 +1401,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1366 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | 1401 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1367 | if (client != null) | 1402 | if (client != null) |
1368 | client.SceneAgent.SendInitialDataToMe(); | 1403 | client.SceneAgent.SendInitialDataToMe(); |
1404 | |||
1405 | // Now we know we can handle more data | ||
1406 | Thread.Sleep(200); | ||
1407 | |||
1408 | // Obtain the queue and remove it from the cache | ||
1409 | Queue<UDPPacketBuffer> queue = null; | ||
1410 | |||
1411 | lock (m_pendingCache) | ||
1412 | { | ||
1413 | if (!m_pendingCache.TryGetValue(endPoint, out queue)) | ||
1414 | { | ||
1415 | m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); | ||
1416 | return; | ||
1417 | } | ||
1418 | m_pendingCache.Remove(endPoint); | ||
1419 | } | ||
1420 | |||
1421 | m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); | ||
1422 | |||
1423 | // Reinject queued packets | ||
1424 | while(queue.Count > 0) | ||
1425 | { | ||
1426 | UDPPacketBuffer buf = queue.Dequeue(); | ||
1427 | PacketReceived(buf); | ||
1428 | } | ||
1429 | queue = null; | ||
1369 | } | 1430 | } |
1370 | else | 1431 | else |
1371 | { | 1432 | { |
@@ -1373,6 +1434,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1373 | m_log.WarnFormat( | 1434 | m_log.WarnFormat( |
1374 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", | 1435 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", |
1375 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); | 1436 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); |
1437 | lock (m_pendingCache) | ||
1438 | m_pendingCache.Remove(endPoint); | ||
1376 | } | 1439 | } |
1377 | 1440 | ||
1378 | // m_log.DebugFormat( | 1441 | // m_log.DebugFormat( |
@@ -1491,7 +1554,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1491 | if (!client.SceneAgent.IsChildAgent) | 1554 | if (!client.SceneAgent.IsChildAgent) |
1492 | client.Kick("Simulator logged you out due to connection timeout"); | 1555 | client.Kick("Simulator logged you out due to connection timeout"); |
1493 | 1556 | ||
1494 | client.CloseWithoutChecks(); | 1557 | client.CloseWithoutChecks(true); |
1495 | } | 1558 | } |
1496 | } | 1559 | } |
1497 | 1560 | ||
@@ -1503,6 +1566,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1503 | 1566 | ||
1504 | while (IsRunningInbound) | 1567 | while (IsRunningInbound) |
1505 | { | 1568 | { |
1569 | m_scene.ThreadAlive(1); | ||
1506 | try | 1570 | try |
1507 | { | 1571 | { |
1508 | IncomingPacket incomingPacket = null; | 1572 | IncomingPacket incomingPacket = null; |
@@ -1550,6 +1614,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1550 | 1614 | ||
1551 | while (base.IsRunningOutbound) | 1615 | while (base.IsRunningOutbound) |
1552 | { | 1616 | { |
1617 | m_scene.ThreadAlive(2); | ||
1553 | try | 1618 | try |
1554 | { | 1619 | { |
1555 | m_packetSent = false; | 1620 | m_packetSent = false; |
@@ -1780,8 +1845,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1780 | Packet packet = incomingPacket.Packet; | 1845 | Packet packet = incomingPacket.Packet; |
1781 | LLClientView client = incomingPacket.Client; | 1846 | LLClientView client = incomingPacket.Client; |
1782 | 1847 | ||
1783 | if (client.IsActive) | 1848 | // if (client.IsActive) |
1784 | { | 1849 | // { |
1785 | m_currentIncomingClient = client; | 1850 | m_currentIncomingClient = client; |
1786 | 1851 | ||
1787 | try | 1852 | try |
@@ -1808,13 +1873,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1808 | { | 1873 | { |
1809 | m_currentIncomingClient = null; | 1874 | m_currentIncomingClient = null; |
1810 | } | 1875 | } |
1811 | } | 1876 | // } |
1812 | else | 1877 | // else |
1813 | { | 1878 | // { |
1814 | m_log.DebugFormat( | 1879 | // m_log.DebugFormat( |
1815 | "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", | 1880 | // "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", |
1816 | packet.Type, client.Name, m_scene.RegionInfo.RegionName); | 1881 | // packet.Type, client.Name, m_scene.RegionInfo.RegionName); |
1817 | } | 1882 | // } |
1818 | 1883 | ||
1819 | IncomingPacketsProcessed++; | 1884 | IncomingPacketsProcessed++; |
1820 | } | 1885 | } |
@@ -1826,8 +1891,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1826 | if (!client.IsLoggingOut) | 1891 | if (!client.IsLoggingOut) |
1827 | { | 1892 | { |
1828 | client.IsLoggingOut = true; | 1893 | client.IsLoggingOut = true; |
1829 | client.Close(); | 1894 | client.Close(false, false); |
1895 | } | ||
1896 | } | ||
1897 | } | ||
1898 | |||
1899 | internal class DoubleQueue<T> where T:class | ||
1900 | { | ||
1901 | private Queue<T> m_lowQueue = new Queue<T>(); | ||
1902 | private Queue<T> m_highQueue = new Queue<T>(); | ||
1903 | |||
1904 | private object m_syncRoot = new object(); | ||
1905 | private Semaphore m_s = new Semaphore(0, 1); | ||
1906 | |||
1907 | public DoubleQueue() | ||
1908 | { | ||
1909 | } | ||
1910 | |||
1911 | public virtual int Count | ||
1912 | { | ||
1913 | get { return m_highQueue.Count + m_lowQueue.Count; } | ||
1914 | } | ||
1915 | |||
1916 | public virtual void Enqueue(T data) | ||
1917 | { | ||
1918 | Enqueue(m_lowQueue, data); | ||
1919 | } | ||
1920 | |||
1921 | public virtual void EnqueueLow(T data) | ||
1922 | { | ||
1923 | Enqueue(m_lowQueue, data); | ||
1924 | } | ||
1925 | |||
1926 | public virtual void EnqueueHigh(T data) | ||
1927 | { | ||
1928 | Enqueue(m_highQueue, data); | ||
1929 | } | ||
1930 | |||
1931 | private void Enqueue(Queue<T> q, T data) | ||
1932 | { | ||
1933 | lock (m_syncRoot) | ||
1934 | { | ||
1935 | m_lowQueue.Enqueue(data); | ||
1936 | m_s.WaitOne(0); | ||
1937 | m_s.Release(); | ||
1938 | } | ||
1939 | } | ||
1940 | |||
1941 | public virtual T Dequeue() | ||
1942 | { | ||
1943 | return Dequeue(Timeout.Infinite); | ||
1944 | } | ||
1945 | |||
1946 | public virtual T Dequeue(int tmo) | ||
1947 | { | ||
1948 | return Dequeue(TimeSpan.FromMilliseconds(tmo)); | ||
1949 | } | ||
1950 | |||
1951 | public virtual T Dequeue(TimeSpan wait) | ||
1952 | { | ||
1953 | T res = null; | ||
1954 | |||
1955 | if (!Dequeue(wait, ref res)) | ||
1956 | return null; | ||
1957 | |||
1958 | return res; | ||
1959 | } | ||
1960 | |||
1961 | public bool Dequeue(int timeout, ref T res) | ||
1962 | { | ||
1963 | return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res); | ||
1964 | } | ||
1965 | |||
1966 | public bool Dequeue(TimeSpan wait, ref T res) | ||
1967 | { | ||
1968 | if (!m_s.WaitOne(wait)) | ||
1969 | return false; | ||
1970 | |||
1971 | lock (m_syncRoot) | ||
1972 | { | ||
1973 | if (m_highQueue.Count > 0) | ||
1974 | res = m_highQueue.Dequeue(); | ||
1975 | else | ||
1976 | res = m_lowQueue.Dequeue(); | ||
1977 | |||
1978 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) | ||
1979 | return true; | ||
1980 | |||
1981 | try | ||
1982 | { | ||
1983 | m_s.Release(); | ||
1984 | } | ||
1985 | catch | ||
1986 | { | ||
1987 | } | ||
1988 | |||
1989 | return true; | ||
1990 | } | ||
1991 | } | ||
1992 | |||
1993 | public virtual void Clear() | ||
1994 | { | ||
1995 | |||
1996 | lock (m_syncRoot) | ||
1997 | { | ||
1998 | // Make sure sem count is 0 | ||
1999 | m_s.WaitOne(0); | ||
2000 | |||
2001 | m_lowQueue.Clear(); | ||
2002 | m_highQueue.Clear(); | ||
1830 | } | 2003 | } |
1831 | } | 2004 | } |
1832 | } | 2005 | } |
1833 | } \ No newline at end of file | 2006 | } |