diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 218 |
1 files changed, 197 insertions, 21 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 55780d6..60ab70e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -110,7 +110,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
110 | /// <summary>Handlers for incoming packets</summary> | 110 | /// <summary>Handlers for incoming packets</summary> |
111 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); | 111 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); |
112 | /// <summary>Incoming packets that are awaiting handling</summary> | 112 | /// <summary>Incoming packets that are awaiting handling</summary> |
113 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); | 113 | //private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); |
114 | |||
115 | private DoubleQueue<IncomingPacket> packetInbox = new DoubleQueue<IncomingPacket>(); | ||
116 | |||
114 | /// <summary></summary> | 117 | /// <summary></summary> |
115 | //private UDPClientCollection m_clients = new UDPClientCollection(); | 118 | //private UDPClientCollection m_clients = new UDPClientCollection(); |
116 | /// <summary>Bandwidth throttle for this UDP server</summary> | 119 | /// <summary>Bandwidth throttle for this UDP server</summary> |
@@ -155,6 +158,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
155 | /// <summary>Flag to signal when clients should send pings</summary> | 158 | /// <summary>Flag to signal when clients should send pings</summary> |
156 | protected bool m_sendPing; | 159 | protected bool m_sendPing; |
157 | 160 | ||
161 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); | ||
162 | |||
158 | private int m_defaultRTO = 0; | 163 | private int m_defaultRTO = 0; |
159 | private int m_maxRTO = 0; | 164 | private int m_maxRTO = 0; |
160 | private int m_ackTimeout = 0; | 165 | private int m_ackTimeout = 0; |
@@ -765,19 +770,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
765 | 770 | ||
766 | #region Packet to Client Mapping | 771 | #region Packet to Client Mapping |
767 | 772 | ||
768 | // UseCircuitCode handling | 773 | // If there is already a client for this endpoint, don't process UseCircuitCode |
769 | if (packet.Type == PacketType.UseCircuitCode) | 774 | IClientAPI client = null; |
775 | if (!m_scene.TryGetClient(address, out client)) | ||
770 | { | 776 | { |
771 | object[] array = new object[] { buffer, packet }; | 777 | // UseCircuitCode handling |
778 | if (packet.Type == PacketType.UseCircuitCode) | ||
779 | { | ||
780 | // And if there is a UseCircuitCode pending, also drop it | ||
781 | lock (m_pendingCache) | ||
782 | { | ||
783 | if (m_pendingCache.Contains(address)) | ||
784 | return; | ||
772 | 785 | ||
773 | Util.FireAndForget(HandleUseCircuitCode, array); | 786 | m_pendingCache.AddOrUpdate(address, new Queue<UDPPacketBuffer>(), 60); |
787 | } | ||
774 | 788 | ||
775 | return; | 789 | object[] array = new object[] { buffer, packet }; |
790 | |||
791 | Util.FireAndForget(HandleUseCircuitCode, array); | ||
792 | |||
793 | return; | ||
794 | } | ||
795 | } | ||
796 | |||
797 | // If this is a pending connection, enqueue, don't process yet | ||
798 | lock (m_pendingCache) | ||
799 | { | ||
800 | Queue<UDPPacketBuffer> queue; | ||
801 | if (m_pendingCache.TryGetValue(address, out queue)) | ||
802 | { | ||
803 | //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); | ||
804 | queue.Enqueue(buffer); | ||
805 | return; | ||
806 | } | ||
776 | } | 807 | } |
777 | 808 | ||
778 | // Determine which agent this packet came from | 809 | // Determine which agent this packet came from |
779 | IClientAPI client; | 810 | if (client == null || !(client is LLClientView)) |
780 | if (!m_scene.TryGetClient(address, out client) || !(client is LLClientView)) | ||
781 | { | 811 | { |
782 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 812 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
783 | return; | 813 | return; |
@@ -786,7 +816,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
786 | udpClient = ((LLClientView)client).UDPClient; | 816 | udpClient = ((LLClientView)client).UDPClient; |
787 | 817 | ||
788 | if (!udpClient.IsConnected) | 818 | if (!udpClient.IsConnected) |
819 | { | ||
820 | // m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName); | ||
789 | return; | 821 | return; |
822 | } | ||
790 | 823 | ||
791 | #endregion Packet to Client Mapping | 824 | #endregion Packet to Client Mapping |
792 | 825 | ||
@@ -889,7 +922,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
889 | #endregion Ping Check Handling | 922 | #endregion Ping Check Handling |
890 | 923 | ||
891 | // Inbox insertion | 924 | // Inbox insertion |
892 | packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet)); | 925 | if (packet.Type == PacketType.AgentUpdate || |
926 | packet.Type == PacketType.ChatFromViewer) | ||
927 | packetInbox.EnqueueHigh(new IncomingPacket((LLClientView)client, packet)); | ||
928 | else | ||
929 | packetInbox.EnqueueLow(new IncomingPacket((LLClientView)client, packet)); | ||
930 | // packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet)); | ||
893 | } | 931 | } |
894 | 932 | ||
895 | #region BinaryStats | 933 | #region BinaryStats |
@@ -1011,6 +1049,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1011 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | 1049 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1012 | if (client != null) | 1050 | if (client != null) |
1013 | client.SceneAgent.SendInitialDataToMe(); | 1051 | client.SceneAgent.SendInitialDataToMe(); |
1052 | |||
1053 | // Now we know we can handle more data | ||
1054 | Thread.Sleep(200); | ||
1055 | |||
1056 | // Obtain the queue and remove it from the cache | ||
1057 | Queue<UDPPacketBuffer> queue = null; | ||
1058 | |||
1059 | lock (m_pendingCache) | ||
1060 | { | ||
1061 | if (!m_pendingCache.TryGetValue(remoteEndPoint, out queue)) | ||
1062 | { | ||
1063 | m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); | ||
1064 | return; | ||
1065 | } | ||
1066 | m_pendingCache.Remove(remoteEndPoint); | ||
1067 | } | ||
1068 | |||
1069 | m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); | ||
1070 | |||
1071 | // Reinject queued packets | ||
1072 | while(queue.Count > 0) | ||
1073 | { | ||
1074 | UDPPacketBuffer buf = queue.Dequeue(); | ||
1075 | PacketReceived(buf); | ||
1076 | } | ||
1077 | queue = null; | ||
1014 | } | 1078 | } |
1015 | else | 1079 | else |
1016 | { | 1080 | { |
@@ -1018,6 +1082,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1018 | m_log.WarnFormat( | 1082 | m_log.WarnFormat( |
1019 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", | 1083 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", |
1020 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); | 1084 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); |
1085 | lock (m_pendingCache) | ||
1086 | m_pendingCache.Remove(remoteEndPoint); | ||
1021 | } | 1087 | } |
1022 | 1088 | ||
1023 | // m_log.DebugFormat( | 1089 | // m_log.DebugFormat( |
@@ -1136,7 +1202,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1136 | if (!client.SceneAgent.IsChildAgent) | 1202 | if (!client.SceneAgent.IsChildAgent) |
1137 | client.Kick("Simulator logged you out due to connection timeout"); | 1203 | client.Kick("Simulator logged you out due to connection timeout"); |
1138 | 1204 | ||
1139 | client.CloseWithoutChecks(); | 1205 | client.CloseWithoutChecks(true); |
1140 | } | 1206 | } |
1141 | } | 1207 | } |
1142 | 1208 | ||
@@ -1148,6 +1214,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1148 | 1214 | ||
1149 | while (base.IsRunning) | 1215 | while (base.IsRunning) |
1150 | { | 1216 | { |
1217 | m_scene.ThreadAlive(1); | ||
1151 | try | 1218 | try |
1152 | { | 1219 | { |
1153 | IncomingPacket incomingPacket = null; | 1220 | IncomingPacket incomingPacket = null; |
@@ -1190,6 +1257,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1190 | 1257 | ||
1191 | while (base.IsRunning) | 1258 | while (base.IsRunning) |
1192 | { | 1259 | { |
1260 | m_scene.ThreadAlive(2); | ||
1193 | try | 1261 | try |
1194 | { | 1262 | { |
1195 | m_packetSent = false; | 1263 | m_packetSent = false; |
@@ -1411,8 +1479,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1411 | Packet packet = incomingPacket.Packet; | 1479 | Packet packet = incomingPacket.Packet; |
1412 | LLClientView client = incomingPacket.Client; | 1480 | LLClientView client = incomingPacket.Client; |
1413 | 1481 | ||
1414 | if (client.IsActive) | 1482 | // if (client.IsActive) |
1415 | { | 1483 | // { |
1416 | m_currentIncomingClient = client; | 1484 | m_currentIncomingClient = client; |
1417 | 1485 | ||
1418 | try | 1486 | try |
@@ -1439,13 +1507,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1439 | { | 1507 | { |
1440 | m_currentIncomingClient = null; | 1508 | m_currentIncomingClient = null; |
1441 | } | 1509 | } |
1442 | } | 1510 | // } |
1443 | else | 1511 | // else |
1444 | { | 1512 | // { |
1445 | m_log.DebugFormat( | 1513 | // m_log.DebugFormat( |
1446 | "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", | 1514 | // "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", |
1447 | packet.Type, client.Name, m_scene.RegionInfo.RegionName); | 1515 | // packet.Type, client.Name, m_scene.RegionInfo.RegionName); |
1448 | } | 1516 | // } |
1449 | } | 1517 | } |
1450 | 1518 | ||
1451 | protected void LogoutHandler(IClientAPI client) | 1519 | protected void LogoutHandler(IClientAPI client) |
@@ -1455,8 +1523,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1455 | if (!client.IsLoggingOut) | 1523 | if (!client.IsLoggingOut) |
1456 | { | 1524 | { |
1457 | client.IsLoggingOut = true; | 1525 | client.IsLoggingOut = true; |
1458 | client.Close(); | 1526 | client.Close(false, false); |
1527 | } | ||
1528 | } | ||
1529 | } | ||
1530 | |||
1531 | internal class DoubleQueue<T> where T:class | ||
1532 | { | ||
1533 | private Queue<T> m_lowQueue = new Queue<T>(); | ||
1534 | private Queue<T> m_highQueue = new Queue<T>(); | ||
1535 | |||
1536 | private object m_syncRoot = new object(); | ||
1537 | private Semaphore m_s = new Semaphore(0, 1); | ||
1538 | |||
1539 | public DoubleQueue() | ||
1540 | { | ||
1541 | } | ||
1542 | |||
1543 | public virtual int Count | ||
1544 | { | ||
1545 | get { return m_highQueue.Count + m_lowQueue.Count; } | ||
1546 | } | ||
1547 | |||
1548 | public virtual void Enqueue(T data) | ||
1549 | { | ||
1550 | Enqueue(m_lowQueue, data); | ||
1551 | } | ||
1552 | |||
1553 | public virtual void EnqueueLow(T data) | ||
1554 | { | ||
1555 | Enqueue(m_lowQueue, data); | ||
1556 | } | ||
1557 | |||
1558 | public virtual void EnqueueHigh(T data) | ||
1559 | { | ||
1560 | Enqueue(m_highQueue, data); | ||
1561 | } | ||
1562 | |||
1563 | private void Enqueue(Queue<T> q, T data) | ||
1564 | { | ||
1565 | lock (m_syncRoot) | ||
1566 | { | ||
1567 | m_lowQueue.Enqueue(data); | ||
1568 | m_s.WaitOne(0); | ||
1569 | m_s.Release(); | ||
1570 | } | ||
1571 | } | ||
1572 | |||
1573 | public virtual T Dequeue() | ||
1574 | { | ||
1575 | return Dequeue(Timeout.Infinite); | ||
1576 | } | ||
1577 | |||
1578 | public virtual T Dequeue(int tmo) | ||
1579 | { | ||
1580 | return Dequeue(TimeSpan.FromMilliseconds(tmo)); | ||
1581 | } | ||
1582 | |||
1583 | public virtual T Dequeue(TimeSpan wait) | ||
1584 | { | ||
1585 | T res = null; | ||
1586 | |||
1587 | if (!Dequeue(wait, ref res)) | ||
1588 | return null; | ||
1589 | |||
1590 | return res; | ||
1591 | } | ||
1592 | |||
1593 | public bool Dequeue(int timeout, ref T res) | ||
1594 | { | ||
1595 | return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res); | ||
1596 | } | ||
1597 | |||
1598 | public bool Dequeue(TimeSpan wait, ref T res) | ||
1599 | { | ||
1600 | if (!m_s.WaitOne(wait)) | ||
1601 | return false; | ||
1602 | |||
1603 | lock (m_syncRoot) | ||
1604 | { | ||
1605 | if (m_highQueue.Count > 0) | ||
1606 | res = m_highQueue.Dequeue(); | ||
1607 | else | ||
1608 | res = m_lowQueue.Dequeue(); | ||
1609 | |||
1610 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) | ||
1611 | return true; | ||
1612 | |||
1613 | try | ||
1614 | { | ||
1615 | m_s.Release(); | ||
1616 | } | ||
1617 | catch | ||
1618 | { | ||
1619 | } | ||
1620 | |||
1621 | return true; | ||
1622 | } | ||
1623 | } | ||
1624 | |||
1625 | public virtual void Clear() | ||
1626 | { | ||
1627 | |||
1628 | lock (m_syncRoot) | ||
1629 | { | ||
1630 | // Make sure sem count is 0 | ||
1631 | m_s.WaitOne(0); | ||
1632 | |||
1633 | m_lowQueue.Clear(); | ||
1634 | m_highQueue.Clear(); | ||
1459 | } | 1635 | } |
1460 | } | 1636 | } |
1461 | } | 1637 | } |
1462 | } \ No newline at end of file | 1638 | } |