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 e3f4679..97b79ce 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -112,7 +112,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
112 | /// <summary>Handlers for incoming packets</summary> | 112 | /// <summary>Handlers for incoming packets</summary> |
113 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); | 113 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); |
114 | /// <summary>Incoming packets that are awaiting handling</summary> | 114 | /// <summary>Incoming packets that are awaiting handling</summary> |
115 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); | 115 | //private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); |
116 | |||
117 | private DoubleQueue<IncomingPacket> packetInbox = new DoubleQueue<IncomingPacket>(); | ||
116 | 118 | ||
117 | /// <summary></summary> | 119 | /// <summary></summary> |
118 | //private UDPClientCollection m_clients = new UDPClientCollection(); | 120 | //private UDPClientCollection m_clients = new UDPClientCollection(); |
@@ -167,6 +169,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
167 | /// <summary>Flag to signal when clients should send pings</summary> | 169 | /// <summary>Flag to signal when clients should send pings</summary> |
168 | protected bool m_sendPing; | 170 | protected bool m_sendPing; |
169 | 171 | ||
172 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); | ||
173 | |||
170 | private int m_defaultRTO = 0; | 174 | private int m_defaultRTO = 0; |
171 | private int m_maxRTO = 0; | 175 | private int m_maxRTO = 0; |
172 | private int m_ackTimeout = 0; | 176 | private int m_ackTimeout = 0; |
@@ -793,19 +797,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
793 | 797 | ||
794 | #region Packet to Client Mapping | 798 | #region Packet to Client Mapping |
795 | 799 | ||
796 | // UseCircuitCode handling | 800 | // If there is already a client for this endpoint, don't process UseCircuitCode |
797 | if (packet.Type == PacketType.UseCircuitCode) | 801 | IClientAPI client = null; |
802 | if (!m_scene.TryGetClient(address, out client)) | ||
798 | { | 803 | { |
799 | object[] array = new object[] { buffer, packet }; | 804 | // UseCircuitCode handling |
805 | if (packet.Type == PacketType.UseCircuitCode) | ||
806 | { | ||
807 | // And if there is a UseCircuitCode pending, also drop it | ||
808 | lock (m_pendingCache) | ||
809 | { | ||
810 | if (m_pendingCache.Contains(address)) | ||
811 | return; | ||
812 | |||
813 | m_pendingCache.AddOrUpdate(address, new Queue<UDPPacketBuffer>(), 60); | ||
814 | } | ||
800 | 815 | ||
801 | Util.FireAndForget(HandleUseCircuitCode, array); | 816 | object[] array = new object[] { buffer, packet }; |
802 | 817 | ||
803 | return; | 818 | Util.FireAndForget(HandleUseCircuitCode, array); |
819 | |||
820 | return; | ||
821 | } | ||
822 | } | ||
823 | |||
824 | // If this is a pending connection, enqueue, don't process yet | ||
825 | lock (m_pendingCache) | ||
826 | { | ||
827 | Queue<UDPPacketBuffer> queue; | ||
828 | if (m_pendingCache.TryGetValue(address, out queue)) | ||
829 | { | ||
830 | //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); | ||
831 | queue.Enqueue(buffer); | ||
832 | return; | ||
833 | } | ||
804 | } | 834 | } |
805 | 835 | ||
806 | // Determine which agent this packet came from | 836 | // Determine which agent this packet came from |
807 | IClientAPI client; | 837 | if (client == null || !(client is LLClientView)) |
808 | if (!m_scene.TryGetClient(address, out client) || !(client is LLClientView)) | ||
809 | { | 838 | { |
810 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 839 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
811 | return; | 840 | return; |
@@ -814,7 +843,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
814 | udpClient = ((LLClientView)client).UDPClient; | 843 | udpClient = ((LLClientView)client).UDPClient; |
815 | 844 | ||
816 | if (!udpClient.IsConnected) | 845 | if (!udpClient.IsConnected) |
846 | { | ||
847 | // m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName); | ||
817 | return; | 848 | return; |
849 | } | ||
818 | 850 | ||
819 | #endregion Packet to Client Mapping | 851 | #endregion Packet to Client Mapping |
820 | 852 | ||
@@ -917,7 +949,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
917 | #endregion Ping Check Handling | 949 | #endregion Ping Check Handling |
918 | 950 | ||
919 | // Inbox insertion | 951 | // Inbox insertion |
920 | packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet)); | 952 | if (packet.Type == PacketType.AgentUpdate || |
953 | packet.Type == PacketType.ChatFromViewer) | ||
954 | packetInbox.EnqueueHigh(new IncomingPacket((LLClientView)client, packet)); | ||
955 | else | ||
956 | packetInbox.EnqueueLow(new IncomingPacket((LLClientView)client, packet)); | ||
957 | // packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet)); | ||
921 | } | 958 | } |
922 | 959 | ||
923 | #region BinaryStats | 960 | #region BinaryStats |
@@ -1039,6 +1076,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1039 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | 1076 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1040 | if (client != null) | 1077 | if (client != null) |
1041 | client.SceneAgent.SendInitialDataToMe(); | 1078 | client.SceneAgent.SendInitialDataToMe(); |
1079 | |||
1080 | // Now we know we can handle more data | ||
1081 | Thread.Sleep(200); | ||
1082 | |||
1083 | // Obtain the queue and remove it from the cache | ||
1084 | Queue<UDPPacketBuffer> queue = null; | ||
1085 | |||
1086 | lock (m_pendingCache) | ||
1087 | { | ||
1088 | if (!m_pendingCache.TryGetValue(remoteEndPoint, out queue)) | ||
1089 | { | ||
1090 | m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); | ||
1091 | return; | ||
1092 | } | ||
1093 | m_pendingCache.Remove(remoteEndPoint); | ||
1094 | } | ||
1095 | |||
1096 | m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); | ||
1097 | |||
1098 | // Reinject queued packets | ||
1099 | while(queue.Count > 0) | ||
1100 | { | ||
1101 | UDPPacketBuffer buf = queue.Dequeue(); | ||
1102 | PacketReceived(buf); | ||
1103 | } | ||
1104 | queue = null; | ||
1042 | } | 1105 | } |
1043 | else | 1106 | else |
1044 | { | 1107 | { |
@@ -1046,6 +1109,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1046 | m_log.WarnFormat( | 1109 | m_log.WarnFormat( |
1047 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", | 1110 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", |
1048 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); | 1111 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); |
1112 | lock (m_pendingCache) | ||
1113 | m_pendingCache.Remove(remoteEndPoint); | ||
1049 | } | 1114 | } |
1050 | 1115 | ||
1051 | // m_log.DebugFormat( | 1116 | // m_log.DebugFormat( |
@@ -1164,7 +1229,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1164 | if (!client.SceneAgent.IsChildAgent) | 1229 | if (!client.SceneAgent.IsChildAgent) |
1165 | client.Kick("Simulator logged you out due to connection timeout"); | 1230 | client.Kick("Simulator logged you out due to connection timeout"); |
1166 | 1231 | ||
1167 | client.CloseWithoutChecks(); | 1232 | client.CloseWithoutChecks(true); |
1168 | } | 1233 | } |
1169 | } | 1234 | } |
1170 | 1235 | ||
@@ -1176,6 +1241,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1176 | 1241 | ||
1177 | while (base.IsRunning) | 1242 | while (base.IsRunning) |
1178 | { | 1243 | { |
1244 | m_scene.ThreadAlive(1); | ||
1179 | try | 1245 | try |
1180 | { | 1246 | { |
1181 | IncomingPacket incomingPacket = null; | 1247 | IncomingPacket incomingPacket = null; |
@@ -1218,6 +1284,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1218 | 1284 | ||
1219 | while (base.IsRunning) | 1285 | while (base.IsRunning) |
1220 | { | 1286 | { |
1287 | m_scene.ThreadAlive(2); | ||
1221 | try | 1288 | try |
1222 | { | 1289 | { |
1223 | m_packetSent = false; | 1290 | m_packetSent = false; |
@@ -1439,8 +1506,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1439 | Packet packet = incomingPacket.Packet; | 1506 | Packet packet = incomingPacket.Packet; |
1440 | LLClientView client = incomingPacket.Client; | 1507 | LLClientView client = incomingPacket.Client; |
1441 | 1508 | ||
1442 | if (client.IsActive) | 1509 | // if (client.IsActive) |
1443 | { | 1510 | // { |
1444 | m_currentIncomingClient = client; | 1511 | m_currentIncomingClient = client; |
1445 | 1512 | ||
1446 | try | 1513 | try |
@@ -1467,13 +1534,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1467 | { | 1534 | { |
1468 | m_currentIncomingClient = null; | 1535 | m_currentIncomingClient = null; |
1469 | } | 1536 | } |
1470 | } | 1537 | // } |
1471 | else | 1538 | // else |
1472 | { | 1539 | // { |
1473 | m_log.DebugFormat( | 1540 | // m_log.DebugFormat( |
1474 | "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", | 1541 | // "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", |
1475 | packet.Type, client.Name, m_scene.RegionInfo.RegionName); | 1542 | // packet.Type, client.Name, m_scene.RegionInfo.RegionName); |
1476 | } | 1543 | // } |
1477 | } | 1544 | } |
1478 | 1545 | ||
1479 | protected void LogoutHandler(IClientAPI client) | 1546 | protected void LogoutHandler(IClientAPI client) |
@@ -1483,8 +1550,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1483 | if (!client.IsLoggingOut) | 1550 | if (!client.IsLoggingOut) |
1484 | { | 1551 | { |
1485 | client.IsLoggingOut = true; | 1552 | client.IsLoggingOut = true; |
1486 | client.Close(); | 1553 | client.Close(false, false); |
1554 | } | ||
1555 | } | ||
1556 | } | ||
1557 | |||
1558 | internal class DoubleQueue<T> where T:class | ||
1559 | { | ||
1560 | private Queue<T> m_lowQueue = new Queue<T>(); | ||
1561 | private Queue<T> m_highQueue = new Queue<T>(); | ||
1562 | |||
1563 | private object m_syncRoot = new object(); | ||
1564 | private Semaphore m_s = new Semaphore(0, 1); | ||
1565 | |||
1566 | public DoubleQueue() | ||
1567 | { | ||
1568 | } | ||
1569 | |||
1570 | public virtual int Count | ||
1571 | { | ||
1572 | get { return m_highQueue.Count + m_lowQueue.Count; } | ||
1573 | } | ||
1574 | |||
1575 | public virtual void Enqueue(T data) | ||
1576 | { | ||
1577 | Enqueue(m_lowQueue, data); | ||
1578 | } | ||
1579 | |||
1580 | public virtual void EnqueueLow(T data) | ||
1581 | { | ||
1582 | Enqueue(m_lowQueue, data); | ||
1583 | } | ||
1584 | |||
1585 | public virtual void EnqueueHigh(T data) | ||
1586 | { | ||
1587 | Enqueue(m_highQueue, data); | ||
1588 | } | ||
1589 | |||
1590 | private void Enqueue(Queue<T> q, T data) | ||
1591 | { | ||
1592 | lock (m_syncRoot) | ||
1593 | { | ||
1594 | m_lowQueue.Enqueue(data); | ||
1595 | m_s.WaitOne(0); | ||
1596 | m_s.Release(); | ||
1597 | } | ||
1598 | } | ||
1599 | |||
1600 | public virtual T Dequeue() | ||
1601 | { | ||
1602 | return Dequeue(Timeout.Infinite); | ||
1603 | } | ||
1604 | |||
1605 | public virtual T Dequeue(int tmo) | ||
1606 | { | ||
1607 | return Dequeue(TimeSpan.FromMilliseconds(tmo)); | ||
1608 | } | ||
1609 | |||
1610 | public virtual T Dequeue(TimeSpan wait) | ||
1611 | { | ||
1612 | T res = null; | ||
1613 | |||
1614 | if (!Dequeue(wait, ref res)) | ||
1615 | return null; | ||
1616 | |||
1617 | return res; | ||
1618 | } | ||
1619 | |||
1620 | public bool Dequeue(int timeout, ref T res) | ||
1621 | { | ||
1622 | return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res); | ||
1623 | } | ||
1624 | |||
1625 | public bool Dequeue(TimeSpan wait, ref T res) | ||
1626 | { | ||
1627 | if (!m_s.WaitOne(wait)) | ||
1628 | return false; | ||
1629 | |||
1630 | lock (m_syncRoot) | ||
1631 | { | ||
1632 | if (m_highQueue.Count > 0) | ||
1633 | res = m_highQueue.Dequeue(); | ||
1634 | else | ||
1635 | res = m_lowQueue.Dequeue(); | ||
1636 | |||
1637 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) | ||
1638 | return true; | ||
1639 | |||
1640 | try | ||
1641 | { | ||
1642 | m_s.Release(); | ||
1643 | } | ||
1644 | catch | ||
1645 | { | ||
1646 | } | ||
1647 | |||
1648 | return true; | ||
1649 | } | ||
1650 | } | ||
1651 | |||
1652 | public virtual void Clear() | ||
1653 | { | ||
1654 | |||
1655 | lock (m_syncRoot) | ||
1656 | { | ||
1657 | // Make sure sem count is 0 | ||
1658 | m_s.WaitOne(0); | ||
1659 | |||
1660 | m_lowQueue.Clear(); | ||
1661 | m_highQueue.Clear(); | ||
1487 | } | 1662 | } |
1488 | } | 1663 | } |
1489 | } | 1664 | } |
1490 | } \ No newline at end of file | 1665 | } |