diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 229 |
1 files changed, 205 insertions, 24 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index a7628d2..6c72edc 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> |
@@ -800,6 +803,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
800 | 803 | ||
801 | #region Queue or Send | 804 | #region Queue or Send |
802 | 805 | ||
806 | bool highPriority = false; | ||
807 | |||
808 | if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0) | ||
809 | { | ||
810 | category = (ThrottleOutPacketType)((int)category & 127); | ||
811 | highPriority = true; | ||
812 | } | ||
813 | |||
803 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); | 814 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); |
804 | // If we were not provided a method for handling unacked, use the UDPServer default method | 815 | // If we were not provided a method for handling unacked, use the UDPServer default method |
805 | outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); | 816 | outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); |
@@ -808,7 +819,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
808 | // continue to display the deleted object until relog. Therefore, we need to always queue a kill object | 819 | // continue to display the deleted object until relog. Therefore, we need to always queue a kill object |
809 | // packet so that it isn't sent before a queued update packet. | 820 | // packet so that it isn't sent before a queued update packet. |
810 | bool requestQueue = type == PacketType.KillObject; | 821 | bool requestQueue = type == PacketType.KillObject; |
811 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) | 822 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority)) |
812 | SendPacketFinal(outgoingPacket); | 823 | SendPacketFinal(outgoingPacket); |
813 | 824 | ||
814 | #endregion Queue or Send | 825 | #endregion Queue or Send |
@@ -1093,21 +1104,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1093 | 1104 | ||
1094 | #region Packet to Client Mapping | 1105 | #region Packet to Client Mapping |
1095 | 1106 | ||
1096 | // UseCircuitCode handling | 1107 | // If there is already a client for this endpoint, don't process UseCircuitCode |
1097 | if (packet.Type == PacketType.UseCircuitCode) | 1108 | IClientAPI client = null; |
1109 | if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) | ||
1098 | { | 1110 | { |
1099 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the | 1111 | // UseCircuitCode handling |
1100 | // buffer. | 1112 | if (packet.Type == PacketType.UseCircuitCode) |
1101 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | 1113 | { |
1114 | // And if there is a UseCircuitCode pending, also drop it | ||
1115 | lock (m_pendingCache) | ||
1116 | { | ||
1117 | if (m_pendingCache.Contains(endPoint)) | ||
1118 | return; | ||
1119 | |||
1120 | m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60); | ||
1121 | } | ||
1102 | 1122 | ||
1103 | Util.FireAndForget(HandleUseCircuitCode, array); | 1123 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the |
1124 | // buffer. | ||
1125 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | ||
1104 | 1126 | ||
1105 | return; | 1127 | Util.FireAndForget(HandleUseCircuitCode, array); |
1128 | |||
1129 | return; | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | // If this is a pending connection, enqueue, don't process yet | ||
1134 | lock (m_pendingCache) | ||
1135 | { | ||
1136 | Queue<UDPPacketBuffer> queue; | ||
1137 | if (m_pendingCache.TryGetValue(endPoint, out queue)) | ||
1138 | { | ||
1139 | //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); | ||
1140 | queue.Enqueue(buffer); | ||
1141 | return; | ||
1142 | } | ||
1106 | } | 1143 | } |
1107 | 1144 | ||
1108 | // Determine which agent this packet came from | 1145 | // Determine which agent this packet came from |
1109 | IClientAPI client; | 1146 | if (client == null || !(client is LLClientView)) |
1110 | if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) | ||
1111 | { | 1147 | { |
1112 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 1148 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
1113 | return; | 1149 | return; |
@@ -1116,7 +1152,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1116 | udpClient = ((LLClientView)client).UDPClient; | 1152 | udpClient = ((LLClientView)client).UDPClient; |
1117 | 1153 | ||
1118 | if (!udpClient.IsConnected) | 1154 | if (!udpClient.IsConnected) |
1155 | { | ||
1156 | // m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName); | ||
1119 | return; | 1157 | return; |
1158 | } | ||
1120 | 1159 | ||
1121 | #endregion Packet to Client Mapping | 1160 | #endregion Packet to Client Mapping |
1122 | 1161 | ||
@@ -1246,7 +1285,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1246 | incomingPacket = new IncomingPacket((LLClientView)client, packet); | 1285 | incomingPacket = new IncomingPacket((LLClientView)client, packet); |
1247 | } | 1286 | } |
1248 | 1287 | ||
1249 | packetInbox.Enqueue(incomingPacket); | 1288 | if (incomingPacket.Packet.Type == PacketType.AgentUpdate || |
1289 | incomingPacket.Packet.Type == PacketType.ChatFromViewer) | ||
1290 | packetInbox.EnqueueHigh(incomingPacket); | ||
1291 | else | ||
1292 | packetInbox.EnqueueLow(incomingPacket); | ||
1250 | } | 1293 | } |
1251 | 1294 | ||
1252 | #region BinaryStats | 1295 | #region BinaryStats |
@@ -1366,6 +1409,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. | 1409 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1367 | if (client != null) | 1410 | if (client != null) |
1368 | client.SceneAgent.SendInitialDataToMe(); | 1411 | client.SceneAgent.SendInitialDataToMe(); |
1412 | |||
1413 | // Now we know we can handle more data | ||
1414 | Thread.Sleep(200); | ||
1415 | |||
1416 | // Obtain the queue and remove it from the cache | ||
1417 | Queue<UDPPacketBuffer> queue = null; | ||
1418 | |||
1419 | lock (m_pendingCache) | ||
1420 | { | ||
1421 | if (!m_pendingCache.TryGetValue(endPoint, out queue)) | ||
1422 | { | ||
1423 | m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); | ||
1424 | return; | ||
1425 | } | ||
1426 | m_pendingCache.Remove(endPoint); | ||
1427 | } | ||
1428 | |||
1429 | m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); | ||
1430 | |||
1431 | // Reinject queued packets | ||
1432 | while(queue.Count > 0) | ||
1433 | { | ||
1434 | UDPPacketBuffer buf = queue.Dequeue(); | ||
1435 | PacketReceived(buf); | ||
1436 | } | ||
1437 | queue = null; | ||
1369 | } | 1438 | } |
1370 | else | 1439 | else |
1371 | { | 1440 | { |
@@ -1373,6 +1442,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1373 | m_log.WarnFormat( | 1442 | m_log.WarnFormat( |
1374 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", | 1443 | "[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); | 1444 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); |
1445 | lock (m_pendingCache) | ||
1446 | m_pendingCache.Remove(endPoint); | ||
1376 | } | 1447 | } |
1377 | 1448 | ||
1378 | // m_log.DebugFormat( | 1449 | // m_log.DebugFormat( |
@@ -1491,7 +1562,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1491 | if (!client.SceneAgent.IsChildAgent) | 1562 | if (!client.SceneAgent.IsChildAgent) |
1492 | client.Kick("Simulator logged you out due to connection timeout"); | 1563 | client.Kick("Simulator logged you out due to connection timeout"); |
1493 | 1564 | ||
1494 | client.CloseWithoutChecks(); | 1565 | client.CloseWithoutChecks(true); |
1495 | } | 1566 | } |
1496 | } | 1567 | } |
1497 | 1568 | ||
@@ -1503,6 +1574,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1503 | 1574 | ||
1504 | while (IsRunningInbound) | 1575 | while (IsRunningInbound) |
1505 | { | 1576 | { |
1577 | m_scene.ThreadAlive(1); | ||
1506 | try | 1578 | try |
1507 | { | 1579 | { |
1508 | IncomingPacket incomingPacket = null; | 1580 | IncomingPacket incomingPacket = null; |
@@ -1550,6 +1622,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1550 | 1622 | ||
1551 | while (base.IsRunningOutbound) | 1623 | while (base.IsRunningOutbound) |
1552 | { | 1624 | { |
1625 | m_scene.ThreadAlive(2); | ||
1553 | try | 1626 | try |
1554 | { | 1627 | { |
1555 | m_packetSent = false; | 1628 | m_packetSent = false; |
@@ -1780,8 +1853,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1780 | Packet packet = incomingPacket.Packet; | 1853 | Packet packet = incomingPacket.Packet; |
1781 | LLClientView client = incomingPacket.Client; | 1854 | LLClientView client = incomingPacket.Client; |
1782 | 1855 | ||
1783 | if (client.IsActive) | 1856 | // if (client.IsActive) |
1784 | { | 1857 | // { |
1785 | m_currentIncomingClient = client; | 1858 | m_currentIncomingClient = client; |
1786 | 1859 | ||
1787 | try | 1860 | try |
@@ -1808,13 +1881,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1808 | { | 1881 | { |
1809 | m_currentIncomingClient = null; | 1882 | m_currentIncomingClient = null; |
1810 | } | 1883 | } |
1811 | } | 1884 | // } |
1812 | else | 1885 | // else |
1813 | { | 1886 | // { |
1814 | m_log.DebugFormat( | 1887 | // m_log.DebugFormat( |
1815 | "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", | 1888 | // "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", |
1816 | packet.Type, client.Name, m_scene.RegionInfo.RegionName); | 1889 | // packet.Type, client.Name, m_scene.RegionInfo.RegionName); |
1817 | } | 1890 | // } |
1818 | 1891 | ||
1819 | IncomingPacketsProcessed++; | 1892 | IncomingPacketsProcessed++; |
1820 | } | 1893 | } |
@@ -1826,8 +1899,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1826 | if (!client.IsLoggingOut) | 1899 | if (!client.IsLoggingOut) |
1827 | { | 1900 | { |
1828 | client.IsLoggingOut = true; | 1901 | client.IsLoggingOut = true; |
1829 | client.Close(); | 1902 | client.Close(false, false); |
1903 | } | ||
1904 | } | ||
1905 | } | ||
1906 | |||
1907 | internal class DoubleQueue<T> where T:class | ||
1908 | { | ||
1909 | private Queue<T> m_lowQueue = new Queue<T>(); | ||
1910 | private Queue<T> m_highQueue = new Queue<T>(); | ||
1911 | |||
1912 | private object m_syncRoot = new object(); | ||
1913 | private Semaphore m_s = new Semaphore(0, 1); | ||
1914 | |||
1915 | public DoubleQueue() | ||
1916 | { | ||
1917 | } | ||
1918 | |||
1919 | public virtual int Count | ||
1920 | { | ||
1921 | get { return m_highQueue.Count + m_lowQueue.Count; } | ||
1922 | } | ||
1923 | |||
1924 | public virtual void Enqueue(T data) | ||
1925 | { | ||
1926 | Enqueue(m_lowQueue, data); | ||
1927 | } | ||
1928 | |||
1929 | public virtual void EnqueueLow(T data) | ||
1930 | { | ||
1931 | Enqueue(m_lowQueue, data); | ||
1932 | } | ||
1933 | |||
1934 | public virtual void EnqueueHigh(T data) | ||
1935 | { | ||
1936 | Enqueue(m_highQueue, data); | ||
1937 | } | ||
1938 | |||
1939 | private void Enqueue(Queue<T> q, T data) | ||
1940 | { | ||
1941 | lock (m_syncRoot) | ||
1942 | { | ||
1943 | m_lowQueue.Enqueue(data); | ||
1944 | m_s.WaitOne(0); | ||
1945 | m_s.Release(); | ||
1946 | } | ||
1947 | } | ||
1948 | |||
1949 | public virtual T Dequeue() | ||
1950 | { | ||
1951 | return Dequeue(Timeout.Infinite); | ||
1952 | } | ||
1953 | |||
1954 | public virtual T Dequeue(int tmo) | ||
1955 | { | ||
1956 | return Dequeue(TimeSpan.FromMilliseconds(tmo)); | ||
1957 | } | ||
1958 | |||
1959 | public virtual T Dequeue(TimeSpan wait) | ||
1960 | { | ||
1961 | T res = null; | ||
1962 | |||
1963 | if (!Dequeue(wait, ref res)) | ||
1964 | return null; | ||
1965 | |||
1966 | return res; | ||
1967 | } | ||
1968 | |||
1969 | public bool Dequeue(int timeout, ref T res) | ||
1970 | { | ||
1971 | return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res); | ||
1972 | } | ||
1973 | |||
1974 | public bool Dequeue(TimeSpan wait, ref T res) | ||
1975 | { | ||
1976 | if (!m_s.WaitOne(wait)) | ||
1977 | return false; | ||
1978 | |||
1979 | lock (m_syncRoot) | ||
1980 | { | ||
1981 | if (m_highQueue.Count > 0) | ||
1982 | res = m_highQueue.Dequeue(); | ||
1983 | else | ||
1984 | res = m_lowQueue.Dequeue(); | ||
1985 | |||
1986 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) | ||
1987 | return true; | ||
1988 | |||
1989 | try | ||
1990 | { | ||
1991 | m_s.Release(); | ||
1992 | } | ||
1993 | catch | ||
1994 | { | ||
1995 | } | ||
1996 | |||
1997 | return true; | ||
1998 | } | ||
1999 | } | ||
2000 | |||
2001 | public virtual void Clear() | ||
2002 | { | ||
2003 | |||
2004 | lock (m_syncRoot) | ||
2005 | { | ||
2006 | // Make sure sem count is 0 | ||
2007 | m_s.WaitOne(0); | ||
2008 | |||
2009 | m_lowQueue.Clear(); | ||
2010 | m_highQueue.Clear(); | ||
1830 | } | 2011 | } |
1831 | } | 2012 | } |
1832 | } | 2013 | } |
1833 | } \ No newline at end of file | 2014 | } |