diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 217 |
1 files changed, 196 insertions, 21 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index fc6dd4d..1d304db 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,8 @@ 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>>(); | ||
174 | |||
171 | private int m_defaultRTO = 0; | 175 | private int m_defaultRTO = 0; |
172 | private int m_maxRTO = 0; | 176 | private int m_maxRTO = 0; |
173 | private int m_ackTimeout = 0; | 177 | private int m_ackTimeout = 0; |
@@ -881,19 +885,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
881 | 885 | ||
882 | #region Packet to Client Mapping | 886 | #region Packet to Client Mapping |
883 | 887 | ||
884 | // UseCircuitCode handling | 888 | // If there is already a client for this endpoint, don't process UseCircuitCode |
885 | if (packet.Type == PacketType.UseCircuitCode) | 889 | IClientAPI client = null; |
890 | if (!m_scene.TryGetClient(address, out client)) | ||
886 | { | 891 | { |
887 | object[] array = new object[] { buffer, packet }; | 892 | // UseCircuitCode handling |
893 | if (packet.Type == PacketType.UseCircuitCode) | ||
894 | { | ||
895 | // And if there is a UseCircuitCode pending, also drop it | ||
896 | lock (m_pendingCache) | ||
897 | { | ||
898 | if (m_pendingCache.Contains(address)) | ||
899 | return; | ||
900 | |||
901 | m_pendingCache.AddOrUpdate(address, new Queue<UDPPacketBuffer>(), 60); | ||
902 | } | ||
888 | 903 | ||
889 | Util.FireAndForget(HandleUseCircuitCode, array); | 904 | object[] array = new object[] { buffer, packet }; |
890 | 905 | ||
891 | return; | 906 | Util.FireAndForget(HandleUseCircuitCode, array); |
907 | |||
908 | return; | ||
909 | } | ||
910 | } | ||
911 | |||
912 | // If this is a pending connection, enqueue, don't process yet | ||
913 | lock (m_pendingCache) | ||
914 | { | ||
915 | Queue<UDPPacketBuffer> queue; | ||
916 | if (m_pendingCache.TryGetValue(address, out queue)) | ||
917 | { | ||
918 | //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); | ||
919 | queue.Enqueue(buffer); | ||
920 | return; | ||
921 | } | ||
892 | } | 922 | } |
893 | 923 | ||
894 | // Determine which agent this packet came from | 924 | // Determine which agent this packet came from |
895 | IClientAPI client; | 925 | if (client == null || !(client is LLClientView)) |
896 | if (!m_scene.TryGetClient(address, out client) || !(client is LLClientView)) | ||
897 | { | 926 | { |
898 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 927 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
899 | return; | 928 | return; |
@@ -902,7 +931,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
902 | udpClient = ((LLClientView)client).UDPClient; | 931 | udpClient = ((LLClientView)client).UDPClient; |
903 | 932 | ||
904 | if (!udpClient.IsConnected) | 933 | if (!udpClient.IsConnected) |
934 | { | ||
935 | // m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName); | ||
905 | return; | 936 | return; |
937 | } | ||
906 | 938 | ||
907 | #endregion Packet to Client Mapping | 939 | #endregion Packet to Client Mapping |
908 | 940 | ||
@@ -1005,7 +1037,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1005 | #endregion Ping Check Handling | 1037 | #endregion Ping Check Handling |
1006 | 1038 | ||
1007 | // Inbox insertion | 1039 | // Inbox insertion |
1008 | packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet)); | 1040 | if (packet.Type == PacketType.AgentUpdate || |
1041 | packet.Type == PacketType.ChatFromViewer) | ||
1042 | packetInbox.EnqueueHigh(new IncomingPacket((LLClientView)client, packet)); | ||
1043 | else | ||
1044 | packetInbox.EnqueueLow(new IncomingPacket((LLClientView)client, packet)); | ||
1045 | // packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet)); | ||
1009 | } | 1046 | } |
1010 | 1047 | ||
1011 | #region BinaryStats | 1048 | #region BinaryStats |
@@ -1127,6 +1164,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1127 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | 1164 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1128 | if (client != null) | 1165 | if (client != null) |
1129 | client.SceneAgent.SendInitialDataToMe(); | 1166 | client.SceneAgent.SendInitialDataToMe(); |
1167 | |||
1168 | // Now we know we can handle more data | ||
1169 | Thread.Sleep(200); | ||
1170 | |||
1171 | // Obtain the queue and remove it from the cache | ||
1172 | Queue<UDPPacketBuffer> queue = null; | ||
1173 | |||
1174 | lock (m_pendingCache) | ||
1175 | { | ||
1176 | if (!m_pendingCache.TryGetValue(remoteEndPoint, out queue)) | ||
1177 | { | ||
1178 | m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); | ||
1179 | return; | ||
1180 | } | ||
1181 | m_pendingCache.Remove(remoteEndPoint); | ||
1182 | } | ||
1183 | |||
1184 | m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); | ||
1185 | |||
1186 | // Reinject queued packets | ||
1187 | while(queue.Count > 0) | ||
1188 | { | ||
1189 | UDPPacketBuffer buf = queue.Dequeue(); | ||
1190 | PacketReceived(buf); | ||
1191 | } | ||
1192 | queue = null; | ||
1130 | } | 1193 | } |
1131 | else | 1194 | else |
1132 | { | 1195 | { |
@@ -1134,6 +1197,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1134 | m_log.WarnFormat( | 1197 | m_log.WarnFormat( |
1135 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", | 1198 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", |
1136 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); | 1199 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); |
1200 | lock (m_pendingCache) | ||
1201 | m_pendingCache.Remove(remoteEndPoint); | ||
1137 | } | 1202 | } |
1138 | 1203 | ||
1139 | // m_log.DebugFormat( | 1204 | // m_log.DebugFormat( |
@@ -1252,7 +1317,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1252 | if (!client.SceneAgent.IsChildAgent) | 1317 | if (!client.SceneAgent.IsChildAgent) |
1253 | client.Kick("Simulator logged you out due to connection timeout"); | 1318 | client.Kick("Simulator logged you out due to connection timeout"); |
1254 | 1319 | ||
1255 | client.CloseWithoutChecks(); | 1320 | client.CloseWithoutChecks(true); |
1256 | } | 1321 | } |
1257 | } | 1322 | } |
1258 | 1323 | ||
@@ -1264,6 +1329,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1264 | 1329 | ||
1265 | while (base.IsRunningInbound) | 1330 | while (base.IsRunningInbound) |
1266 | { | 1331 | { |
1332 | m_scene.ThreadAlive(1); | ||
1267 | try | 1333 | try |
1268 | { | 1334 | { |
1269 | IncomingPacket incomingPacket = null; | 1335 | IncomingPacket incomingPacket = null; |
@@ -1306,6 +1372,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1306 | 1372 | ||
1307 | while (base.IsRunningOutbound) | 1373 | while (base.IsRunningOutbound) |
1308 | { | 1374 | { |
1375 | m_scene.ThreadAlive(2); | ||
1309 | try | 1376 | try |
1310 | { | 1377 | { |
1311 | m_packetSent = false; | 1378 | m_packetSent = false; |
@@ -1527,8 +1594,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1527 | Packet packet = incomingPacket.Packet; | 1594 | Packet packet = incomingPacket.Packet; |
1528 | LLClientView client = incomingPacket.Client; | 1595 | LLClientView client = incomingPacket.Client; |
1529 | 1596 | ||
1530 | if (client.IsActive) | 1597 | // if (client.IsActive) |
1531 | { | 1598 | // { |
1532 | m_currentIncomingClient = client; | 1599 | m_currentIncomingClient = client; |
1533 | 1600 | ||
1534 | try | 1601 | try |
@@ -1555,13 +1622,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1555 | { | 1622 | { |
1556 | m_currentIncomingClient = null; | 1623 | m_currentIncomingClient = null; |
1557 | } | 1624 | } |
1558 | } | 1625 | // } |
1559 | else | 1626 | // else |
1560 | { | 1627 | // { |
1561 | m_log.DebugFormat( | 1628 | // m_log.DebugFormat( |
1562 | "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", | 1629 | // "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", |
1563 | packet.Type, client.Name, m_scene.RegionInfo.RegionName); | 1630 | // packet.Type, client.Name, m_scene.RegionInfo.RegionName); |
1564 | } | 1631 | // } |
1565 | } | 1632 | } |
1566 | 1633 | ||
1567 | protected void LogoutHandler(IClientAPI client) | 1634 | protected void LogoutHandler(IClientAPI client) |
@@ -1571,8 +1638,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1571 | if (!client.IsLoggingOut) | 1638 | if (!client.IsLoggingOut) |
1572 | { | 1639 | { |
1573 | client.IsLoggingOut = true; | 1640 | client.IsLoggingOut = true; |
1574 | client.Close(); | 1641 | client.Close(false, false); |
1642 | } | ||
1643 | } | ||
1644 | } | ||
1645 | |||
1646 | internal class DoubleQueue<T> where T:class | ||
1647 | { | ||
1648 | private Queue<T> m_lowQueue = new Queue<T>(); | ||
1649 | private Queue<T> m_highQueue = new Queue<T>(); | ||
1650 | |||
1651 | private object m_syncRoot = new object(); | ||
1652 | private Semaphore m_s = new Semaphore(0, 1); | ||
1653 | |||
1654 | public DoubleQueue() | ||
1655 | { | ||
1656 | } | ||
1657 | |||
1658 | public virtual int Count | ||
1659 | { | ||
1660 | get { return m_highQueue.Count + m_lowQueue.Count; } | ||
1661 | } | ||
1662 | |||
1663 | public virtual void Enqueue(T data) | ||
1664 | { | ||
1665 | Enqueue(m_lowQueue, data); | ||
1666 | } | ||
1667 | |||
1668 | public virtual void EnqueueLow(T data) | ||
1669 | { | ||
1670 | Enqueue(m_lowQueue, data); | ||
1671 | } | ||
1672 | |||
1673 | public virtual void EnqueueHigh(T data) | ||
1674 | { | ||
1675 | Enqueue(m_highQueue, data); | ||
1676 | } | ||
1677 | |||
1678 | private void Enqueue(Queue<T> q, T data) | ||
1679 | { | ||
1680 | lock (m_syncRoot) | ||
1681 | { | ||
1682 | m_lowQueue.Enqueue(data); | ||
1683 | m_s.WaitOne(0); | ||
1684 | m_s.Release(); | ||
1685 | } | ||
1686 | } | ||
1687 | |||
1688 | public virtual T Dequeue() | ||
1689 | { | ||
1690 | return Dequeue(Timeout.Infinite); | ||
1691 | } | ||
1692 | |||
1693 | public virtual T Dequeue(int tmo) | ||
1694 | { | ||
1695 | return Dequeue(TimeSpan.FromMilliseconds(tmo)); | ||
1696 | } | ||
1697 | |||
1698 | public virtual T Dequeue(TimeSpan wait) | ||
1699 | { | ||
1700 | T res = null; | ||
1701 | |||
1702 | if (!Dequeue(wait, ref res)) | ||
1703 | return null; | ||
1704 | |||
1705 | return res; | ||
1706 | } | ||
1707 | |||
1708 | public bool Dequeue(int timeout, ref T res) | ||
1709 | { | ||
1710 | return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res); | ||
1711 | } | ||
1712 | |||
1713 | public bool Dequeue(TimeSpan wait, ref T res) | ||
1714 | { | ||
1715 | if (!m_s.WaitOne(wait)) | ||
1716 | return false; | ||
1717 | |||
1718 | lock (m_syncRoot) | ||
1719 | { | ||
1720 | if (m_highQueue.Count > 0) | ||
1721 | res = m_highQueue.Dequeue(); | ||
1722 | else | ||
1723 | res = m_lowQueue.Dequeue(); | ||
1724 | |||
1725 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) | ||
1726 | return true; | ||
1727 | |||
1728 | try | ||
1729 | { | ||
1730 | m_s.Release(); | ||
1731 | } | ||
1732 | catch | ||
1733 | { | ||
1734 | } | ||
1735 | |||
1736 | return true; | ||
1737 | } | ||
1738 | } | ||
1739 | |||
1740 | public virtual void Clear() | ||
1741 | { | ||
1742 | |||
1743 | lock (m_syncRoot) | ||
1744 | { | ||
1745 | // Make sure sem count is 0 | ||
1746 | m_s.WaitOne(0); | ||
1747 | |||
1748 | m_lowQueue.Clear(); | ||
1749 | m_highQueue.Clear(); | ||
1575 | } | 1750 | } |
1576 | } | 1751 | } |
1577 | } | 1752 | } |
1578 | } \ No newline at end of file | 1753 | } |