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 419de66..df4bbb3 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 int m_defaultRTO = 0; | 176 | private int m_defaultRTO = 0; |
@@ -891,21 +894,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
891 | 894 | ||
892 | #region Packet to Client Mapping | 895 | #region Packet to Client Mapping |
893 | 896 | ||
894 | // UseCircuitCode handling | 897 | // If there is already a client for this endpoint, don't process UseCircuitCode |
895 | if (packet.Type == PacketType.UseCircuitCode) | 898 | IClientAPI client = null; |
899 | if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) | ||
896 | { | 900 | { |
897 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the | 901 | // UseCircuitCode handling |
898 | // buffer. | 902 | if (packet.Type == PacketType.UseCircuitCode) |
899 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | 903 | { |
904 | // And if there is a UseCircuitCode pending, also drop it | ||
905 | lock (m_pendingCache) | ||
906 | { | ||
907 | if (m_pendingCache.Contains(endPoint)) | ||
908 | return; | ||
900 | 909 | ||
901 | Util.FireAndForget(HandleUseCircuitCode, array); | 910 | m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60); |
911 | } | ||
902 | 912 | ||
903 | return; | 913 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the |
914 | // buffer. | ||
915 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | ||
916 | |||
917 | Util.FireAndForget(HandleUseCircuitCode, array); | ||
918 | |||
919 | return; | ||
920 | } | ||
921 | } | ||
922 | |||
923 | // If this is a pending connection, enqueue, don't process yet | ||
924 | lock (m_pendingCache) | ||
925 | { | ||
926 | Queue<UDPPacketBuffer> queue; | ||
927 | if (m_pendingCache.TryGetValue(endPoint, out queue)) | ||
928 | { | ||
929 | //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); | ||
930 | queue.Enqueue(buffer); | ||
931 | return; | ||
932 | } | ||
904 | } | 933 | } |
905 | 934 | ||
906 | // Determine which agent this packet came from | 935 | // Determine which agent this packet came from |
907 | IClientAPI client; | 936 | if (client == null || !(client is LLClientView)) |
908 | if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) | ||
909 | { | 937 | { |
910 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 938 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
911 | return; | 939 | return; |
@@ -914,7 +942,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
914 | udpClient = ((LLClientView)client).UDPClient; | 942 | udpClient = ((LLClientView)client).UDPClient; |
915 | 943 | ||
916 | if (!udpClient.IsConnected) | 944 | if (!udpClient.IsConnected) |
945 | { | ||
946 | // m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName); | ||
917 | return; | 947 | return; |
948 | } | ||
918 | 949 | ||
919 | #endregion Packet to Client Mapping | 950 | #endregion Packet to Client Mapping |
920 | 951 | ||
@@ -1044,7 +1075,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1044 | incomingPacket = new IncomingPacket((LLClientView)client, packet); | 1075 | incomingPacket = new IncomingPacket((LLClientView)client, packet); |
1045 | } | 1076 | } |
1046 | 1077 | ||
1047 | packetInbox.Enqueue(incomingPacket); | 1078 | if (incomingPacket.Packet.Type == PacketType.AgentUpdate || |
1079 | incomingPacket.Packet.Type == PacketType.ChatFromViewer) | ||
1080 | packetInbox.EnqueueHigh(incomingPacket); | ||
1081 | else | ||
1082 | packetInbox.EnqueueLow(incomingPacket); | ||
1048 | } | 1083 | } |
1049 | 1084 | ||
1050 | #region BinaryStats | 1085 | #region BinaryStats |
@@ -1164,6 +1199,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1164 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | 1199 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1165 | if (client != null) | 1200 | if (client != null) |
1166 | client.SceneAgent.SendInitialDataToMe(); | 1201 | client.SceneAgent.SendInitialDataToMe(); |
1202 | |||
1203 | // Now we know we can handle more data | ||
1204 | Thread.Sleep(200); | ||
1205 | |||
1206 | // Obtain the queue and remove it from the cache | ||
1207 | Queue<UDPPacketBuffer> queue = null; | ||
1208 | |||
1209 | lock (m_pendingCache) | ||
1210 | { | ||
1211 | if (!m_pendingCache.TryGetValue(endPoint, out queue)) | ||
1212 | { | ||
1213 | m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); | ||
1214 | return; | ||
1215 | } | ||
1216 | m_pendingCache.Remove(endPoint); | ||
1217 | } | ||
1218 | |||
1219 | m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); | ||
1220 | |||
1221 | // Reinject queued packets | ||
1222 | while(queue.Count > 0) | ||
1223 | { | ||
1224 | UDPPacketBuffer buf = queue.Dequeue(); | ||
1225 | PacketReceived(buf); | ||
1226 | } | ||
1227 | queue = null; | ||
1167 | } | 1228 | } |
1168 | else | 1229 | else |
1169 | { | 1230 | { |
@@ -1171,6 +1232,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1171 | m_log.WarnFormat( | 1232 | m_log.WarnFormat( |
1172 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", | 1233 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", |
1173 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); | 1234 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); |
1235 | lock (m_pendingCache) | ||
1236 | m_pendingCache.Remove(endPoint); | ||
1174 | } | 1237 | } |
1175 | 1238 | ||
1176 | // m_log.DebugFormat( | 1239 | // m_log.DebugFormat( |
@@ -1289,7 +1352,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1289 | if (!client.SceneAgent.IsChildAgent) | 1352 | if (!client.SceneAgent.IsChildAgent) |
1290 | client.Kick("Simulator logged you out due to connection timeout"); | 1353 | client.Kick("Simulator logged you out due to connection timeout"); |
1291 | 1354 | ||
1292 | client.CloseWithoutChecks(); | 1355 | client.CloseWithoutChecks(true); |
1293 | } | 1356 | } |
1294 | } | 1357 | } |
1295 | 1358 | ||
@@ -1301,6 +1364,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1301 | 1364 | ||
1302 | while (IsRunningInbound) | 1365 | while (IsRunningInbound) |
1303 | { | 1366 | { |
1367 | m_scene.ThreadAlive(1); | ||
1304 | try | 1368 | try |
1305 | { | 1369 | { |
1306 | IncomingPacket incomingPacket = null; | 1370 | IncomingPacket incomingPacket = null; |
@@ -1348,6 +1412,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1348 | 1412 | ||
1349 | while (base.IsRunningOutbound) | 1413 | while (base.IsRunningOutbound) |
1350 | { | 1414 | { |
1415 | m_scene.ThreadAlive(2); | ||
1351 | try | 1416 | try |
1352 | { | 1417 | { |
1353 | m_packetSent = false; | 1418 | m_packetSent = false; |
@@ -1569,8 +1634,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1569 | Packet packet = incomingPacket.Packet; | 1634 | Packet packet = incomingPacket.Packet; |
1570 | LLClientView client = incomingPacket.Client; | 1635 | LLClientView client = incomingPacket.Client; |
1571 | 1636 | ||
1572 | if (client.IsActive) | 1637 | // if (client.IsActive) |
1573 | { | 1638 | // { |
1574 | m_currentIncomingClient = client; | 1639 | m_currentIncomingClient = client; |
1575 | 1640 | ||
1576 | try | 1641 | try |
@@ -1597,13 +1662,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1597 | { | 1662 | { |
1598 | m_currentIncomingClient = null; | 1663 | m_currentIncomingClient = null; |
1599 | } | 1664 | } |
1600 | } | 1665 | // } |
1601 | else | 1666 | // else |
1602 | { | 1667 | // { |
1603 | m_log.DebugFormat( | 1668 | // m_log.DebugFormat( |
1604 | "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", | 1669 | // "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", |
1605 | packet.Type, client.Name, m_scene.RegionInfo.RegionName); | 1670 | // packet.Type, client.Name, m_scene.RegionInfo.RegionName); |
1606 | } | 1671 | // } |
1607 | } | 1672 | } |
1608 | 1673 | ||
1609 | protected void LogoutHandler(IClientAPI client) | 1674 | protected void LogoutHandler(IClientAPI client) |
@@ -1613,8 +1678,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1613 | if (!client.IsLoggingOut) | 1678 | if (!client.IsLoggingOut) |
1614 | { | 1679 | { |
1615 | client.IsLoggingOut = true; | 1680 | client.IsLoggingOut = true; |
1616 | client.Close(); | 1681 | client.Close(false, false); |
1682 | } | ||
1683 | } | ||
1684 | } | ||
1685 | |||
1686 | internal class DoubleQueue<T> where T:class | ||
1687 | { | ||
1688 | private Queue<T> m_lowQueue = new Queue<T>(); | ||
1689 | private Queue<T> m_highQueue = new Queue<T>(); | ||
1690 | |||
1691 | private object m_syncRoot = new object(); | ||
1692 | private Semaphore m_s = new Semaphore(0, 1); | ||
1693 | |||
1694 | public DoubleQueue() | ||
1695 | { | ||
1696 | } | ||
1697 | |||
1698 | public virtual int Count | ||
1699 | { | ||
1700 | get { return m_highQueue.Count + m_lowQueue.Count; } | ||
1701 | } | ||
1702 | |||
1703 | public virtual void Enqueue(T data) | ||
1704 | { | ||
1705 | Enqueue(m_lowQueue, data); | ||
1706 | } | ||
1707 | |||
1708 | public virtual void EnqueueLow(T data) | ||
1709 | { | ||
1710 | Enqueue(m_lowQueue, data); | ||
1711 | } | ||
1712 | |||
1713 | public virtual void EnqueueHigh(T data) | ||
1714 | { | ||
1715 | Enqueue(m_highQueue, data); | ||
1716 | } | ||
1717 | |||
1718 | private void Enqueue(Queue<T> q, T data) | ||
1719 | { | ||
1720 | lock (m_syncRoot) | ||
1721 | { | ||
1722 | m_lowQueue.Enqueue(data); | ||
1723 | m_s.WaitOne(0); | ||
1724 | m_s.Release(); | ||
1725 | } | ||
1726 | } | ||
1727 | |||
1728 | public virtual T Dequeue() | ||
1729 | { | ||
1730 | return Dequeue(Timeout.Infinite); | ||
1731 | } | ||
1732 | |||
1733 | public virtual T Dequeue(int tmo) | ||
1734 | { | ||
1735 | return Dequeue(TimeSpan.FromMilliseconds(tmo)); | ||
1736 | } | ||
1737 | |||
1738 | public virtual T Dequeue(TimeSpan wait) | ||
1739 | { | ||
1740 | T res = null; | ||
1741 | |||
1742 | if (!Dequeue(wait, ref res)) | ||
1743 | return null; | ||
1744 | |||
1745 | return res; | ||
1746 | } | ||
1747 | |||
1748 | public bool Dequeue(int timeout, ref T res) | ||
1749 | { | ||
1750 | return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res); | ||
1751 | } | ||
1752 | |||
1753 | public bool Dequeue(TimeSpan wait, ref T res) | ||
1754 | { | ||
1755 | if (!m_s.WaitOne(wait)) | ||
1756 | return false; | ||
1757 | |||
1758 | lock (m_syncRoot) | ||
1759 | { | ||
1760 | if (m_highQueue.Count > 0) | ||
1761 | res = m_highQueue.Dequeue(); | ||
1762 | else | ||
1763 | res = m_lowQueue.Dequeue(); | ||
1764 | |||
1765 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) | ||
1766 | return true; | ||
1767 | |||
1768 | try | ||
1769 | { | ||
1770 | m_s.Release(); | ||
1771 | } | ||
1772 | catch | ||
1773 | { | ||
1774 | } | ||
1775 | |||
1776 | return true; | ||
1777 | } | ||
1778 | } | ||
1779 | |||
1780 | public virtual void Clear() | ||
1781 | { | ||
1782 | |||
1783 | lock (m_syncRoot) | ||
1784 | { | ||
1785 | // Make sure sem count is 0 | ||
1786 | m_s.WaitOne(0); | ||
1787 | |||
1788 | m_lowQueue.Clear(); | ||
1789 | m_highQueue.Clear(); | ||
1617 | } | 1790 | } |
1618 | } | 1791 | } |
1619 | } | 1792 | } |
1620 | } \ No newline at end of file | 1793 | } |