aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/Tests
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/ClientStack/Linden/UDP/Tests
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/Tests')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs110
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs17
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs78
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs1
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs170
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs427
6 files changed, 473 insertions, 330 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
index 556df30..a935dd2 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
@@ -33,9 +33,9 @@ using NUnit.Framework;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.Packets; 34using OpenMetaverse.Packets;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
37using OpenSim.Tests.Common; 38using OpenSim.Tests.Common;
38using OpenSim.Tests.Common.Mock;
39 39
40namespace OpenSim.Region.ClientStack.LindenUDP.Tests 40namespace OpenSim.Region.ClientStack.LindenUDP.Tests
41{ 41{
@@ -46,7 +46,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
46 public class BasicCircuitTests : OpenSimTestCase 46 public class BasicCircuitTests : OpenSimTestCase
47 { 47 {
48 private Scene m_scene; 48 private Scene m_scene;
49 private TestLLUDPServer m_udpServer;
50 49
51 [TestFixtureSetUp] 50 [TestFixtureSetUp]
52 public void FixtureInit() 51 public void FixtureInit()
@@ -69,74 +68,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
69 { 68 {
70 base.SetUp(); 69 base.SetUp();
71 m_scene = new SceneHelpers().SetupScene(); 70 m_scene = new SceneHelpers().SetupScene();
71 StatsManager.SimExtraStats = new SimExtraStatsCollector();
72 } 72 }
73 73
74 /// <summary> 74// /// <summary>
75 /// Build an object name packet for test purposes 75// /// Build an object name packet for test purposes
76 /// </summary> 76// /// </summary>
77 /// <param name="objectLocalId"></param> 77// /// <param name="objectLocalId"></param>
78 /// <param name="objectName"></param> 78// /// <param name="objectName"></param>
79 private ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName) 79// private ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName)
80 { 80// {
81 ObjectNamePacket onp = new ObjectNamePacket(); 81// ObjectNamePacket onp = new ObjectNamePacket();
82 ObjectNamePacket.ObjectDataBlock odb = new ObjectNamePacket.ObjectDataBlock(); 82// ObjectNamePacket.ObjectDataBlock odb = new ObjectNamePacket.ObjectDataBlock();
83 odb.LocalID = objectLocalId; 83// odb.LocalID = objectLocalId;
84 odb.Name = Utils.StringToBytes(objectName); 84// odb.Name = Utils.StringToBytes(objectName);
85 onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb }; 85// onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb };
86 onp.Header.Zerocoded = false; 86// onp.Header.Zerocoded = false;
87 87//
88 return onp; 88// return onp;
89 } 89// }
90 90//
91 private void AddUdpServer()
92 {
93 AddUdpServer(new IniConfigSource());
94 }
95
96 private void AddUdpServer(IniConfigSource configSource)
97 {
98 uint port = 0;
99 AgentCircuitManager acm = m_scene.AuthenticateHandler;
100
101 m_udpServer = new TestLLUDPServer(IPAddress.Any, ref port, 0, false, configSource, acm);
102 m_udpServer.AddScene(m_scene);
103 }
104
105 /// <summary>
106 /// Used by tests that aren't testing this stage.
107 /// </summary>
108 private ScenePresence AddClient()
109 {
110 UUID myAgentUuid = TestHelpers.ParseTail(0x1);
111 UUID mySessionUuid = TestHelpers.ParseTail(0x2);
112 uint myCircuitCode = 123456;
113 IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999);
114
115 UseCircuitCodePacket uccp = new UseCircuitCodePacket();
116
117 UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock
118 = new UseCircuitCodePacket.CircuitCodeBlock();
119 uccpCcBlock.Code = myCircuitCode;
120 uccpCcBlock.ID = myAgentUuid;
121 uccpCcBlock.SessionID = mySessionUuid;
122 uccp.CircuitCode = uccpCcBlock;
123
124 byte[] uccpBytes = uccp.ToBytes();
125 UDPPacketBuffer upb = new UDPPacketBuffer(testEp, uccpBytes.Length);
126 upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor.
127 Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length);
128
129 AgentCircuitData acd = new AgentCircuitData();
130 acd.AgentID = myAgentUuid;
131 acd.SessionID = mySessionUuid;
132
133 m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd);
134
135 m_udpServer.PacketReceived(upb);
136
137 return m_scene.GetScenePresence(myAgentUuid);
138 }
139
140 /// <summary> 91 /// <summary>
141 /// Test adding a client to the stack 92 /// Test adding a client to the stack
142 /// </summary> 93 /// </summary>
@@ -146,7 +97,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
146 TestHelpers.InMethod(); 97 TestHelpers.InMethod();
147// TestHelpers.EnableLogging(); 98// TestHelpers.EnableLogging();
148 99
149 AddUdpServer(); 100 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene);
150 101
151 UUID myAgentUuid = TestHelpers.ParseTail(0x1); 102 UUID myAgentUuid = TestHelpers.ParseTail(0x1);
152 UUID mySessionUuid = TestHelpers.ParseTail(0x2); 103 UUID mySessionUuid = TestHelpers.ParseTail(0x2);
@@ -167,7 +118,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
167 upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor. 118 upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor.
168 Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length); 119 Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length);
169 120
170 m_udpServer.PacketReceived(upb); 121 udpServer.PacketReceived(upb);
171 122
172 // Presence shouldn't exist since the circuit manager doesn't know about this circuit for authentication yet 123 // Presence shouldn't exist since the circuit manager doesn't know about this circuit for authentication yet
173 Assert.That(m_scene.GetScenePresence(myAgentUuid), Is.Null); 124 Assert.That(m_scene.GetScenePresence(myAgentUuid), Is.Null);
@@ -178,15 +129,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
178 129
179 m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd); 130 m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd);
180 131
181 m_udpServer.PacketReceived(upb); 132 udpServer.PacketReceived(upb);
182 133
183 // Should succeed now 134 // Should succeed now
184 ScenePresence sp = m_scene.GetScenePresence(myAgentUuid); 135 ScenePresence sp = m_scene.GetScenePresence(myAgentUuid);
185 Assert.That(sp.UUID, Is.EqualTo(myAgentUuid)); 136 Assert.That(sp.UUID, Is.EqualTo(myAgentUuid));
186 137
187 Assert.That(m_udpServer.PacketsSent.Count, Is.EqualTo(1)); 138 Assert.That(udpServer.PacketsSent.Count, Is.EqualTo(1));
188 139
189 Packet packet = m_udpServer.PacketsSent[0]; 140 Packet packet = udpServer.PacketsSent[0];
190 Assert.That(packet, Is.InstanceOf(typeof(PacketAckPacket))); 141 Assert.That(packet, Is.InstanceOf(typeof(PacketAckPacket)));
191 142
192 PacketAckPacket ackPacket = packet as PacketAckPacket; 143 PacketAckPacket ackPacket = packet as PacketAckPacket;
@@ -203,15 +154,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
203 IniConfigSource ics = new IniConfigSource(); 154 IniConfigSource ics = new IniConfigSource();
204 IConfig config = ics.AddConfig("ClientStack.LindenUDP"); 155 IConfig config = ics.AddConfig("ClientStack.LindenUDP");
205 config.Set("AckTimeout", -1); 156 config.Set("AckTimeout", -1);
206 AddUdpServer(ics); 157 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene, ics);
158
159 ScenePresence sp
160 = ClientStackHelpers.AddChildClient(
161 m_scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
207 162
208 ScenePresence sp = AddClient(); 163 udpServer.ClientOutgoingPacketHandler(sp.ControllingClient, true, false, false);
209 m_udpServer.ClientOutgoingPacketHandler(sp.ControllingClient, true, false, false);
210 164
211 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); 165 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID);
212 Assert.That(spAfterAckTimeout, Is.Null); 166 Assert.That(spAfterAckTimeout, Is.Null);
213
214// TestHelpers.DisableLogging();
215 } 167 }
216 168
217// /// <summary> 169// /// <summary>
@@ -233,7 +185,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
233// testLLUDPServer.RemoveClientCircuit(myCircuitCode); 185// testLLUDPServer.RemoveClientCircuit(myCircuitCode);
234// Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode)); 186// Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode));
235// 187//
236// // Check that removing a non-existant circuit doesn't have any bad effects 188// // Check that removing a non-existent circuit doesn't have any bad effects
237// testLLUDPServer.RemoveClientCircuit(101); 189// testLLUDPServer.RemoveClientCircuit(101);
238// Assert.IsFalse(testLLUDPServer.HasCircuit(101)); 190// Assert.IsFalse(testLLUDPServer.HasCircuit(101));
239// } 191// }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
index 7d9f581..6c57e6d 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
@@ -29,6 +29,7 @@ using System;
29using System.IO; 29using System.IO;
30using System.Net; 30using System.Net;
31using System.Reflection; 31using System.Reflection;
32using System.Threading;
32using log4net.Config; 33using log4net.Config;
33using Nini.Config; 34using Nini.Config;
34using NUnit.Framework; 35using NUnit.Framework;
@@ -38,7 +39,6 @@ using OpenSim.Framework;
38using OpenSim.Region.CoreModules.Agent.TextureSender; 39using OpenSim.Region.CoreModules.Agent.TextureSender;
39using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
40using OpenSim.Tests.Common; 41using OpenSim.Tests.Common;
41using OpenSim.Tests.Common.Mock;
42 42
43namespace OpenSim.Region.ClientStack.LindenUDP.Tests 43namespace OpenSim.Region.ClientStack.LindenUDP.Tests
44{ 44{
@@ -53,6 +53,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
53 [TestFixtureSetUp] 53 [TestFixtureSetUp]
54 public void FixtureInit() 54 public void FixtureInit()
55 { 55 {
56 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
57 Util.FireAndForgetMethod = FireAndForgetMethod.None;
58
56 using ( 59 using (
57 Stream resource 60 Stream resource
58 = GetType().Assembly.GetManifestResourceStream( 61 = GetType().Assembly.GetManifestResourceStream(
@@ -72,9 +75,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
72 } 75 }
73 } 76 }
74 77
78 [TestFixtureTearDown]
79 public void TearDown()
80 {
81 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
82 // threads. Possibly, later tests should be rewritten not to worry about such things.
83 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
84 }
85
75 [SetUp] 86 [SetUp]
76 public void SetUp() 87 public override void SetUp()
77 { 88 {
89 base.SetUp();
90
78 UUID userId = TestHelpers.ParseTail(0x3); 91 UUID userId = TestHelpers.ParseTail(0x3);
79 92
80 J2KDecoderModule j2kdm = new J2KDecoderModule(); 93 J2KDecoderModule j2kdm = new J2KDecoderModule();
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
deleted file mode 100644
index 119a677..0000000
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
+++ /dev/null
@@ -1,78 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Net;
29using OpenMetaverse;
30using OpenSim.Framework;
31using OpenSim.Region.Framework.Scenes;
32using GridRegion = OpenSim.Services.Interfaces.GridRegion;
33
34namespace OpenSim.Region.ClientStack.LindenUDP.Tests
35{
36 /// <summary>
37 /// Mock scene for unit tests
38 /// </summary>
39 public class MockScene : SceneBase
40 {
41 public int ObjectNameCallsReceived
42 {
43 get { return m_objectNameCallsReceived; }
44 }
45 protected int m_objectNameCallsReceived;
46
47 public MockScene() : base(new RegionInfo(1000, 1000, null, null))
48 {
49 m_regStatus = RegionStatus.Up;
50 }
51
52 public override void Update(int frames) {}
53 public override void LoadWorldMap() {}
54
55 public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type)
56 {
57 client.OnObjectName += RecordObjectNameCall;
58
59 // FIXME
60 return null;
61 }
62
63 public override void RemoveClient(UUID agentID, bool someReason) {}
64// public override void CloseAllAgents(uint circuitcode) {}
65 public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; }
66 public override void OtherRegionUp(GridRegion otherRegion) { }
67
68 public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; }
69
70 /// <summary>
71 /// Doesn't really matter what the call is - we're using this to test that a packet has actually been received
72 /// </summary>
73 protected void RecordObjectNameCall(IClientAPI remoteClient, uint localID, string message)
74 {
75 m_objectNameCallsReceived++;
76 }
77 }
78}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
index 5f73a94..92f1fc3 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
@@ -30,7 +30,6 @@ using NUnit.Framework;
30using OpenMetaverse; 30using OpenMetaverse;
31using OpenMetaverse.Packets; 31using OpenMetaverse.Packets;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Tests.Common.Mock;
34using OpenSim.Tests.Common; 33using OpenSim.Tests.Common;
35 34
36namespace OpenSim.Region.ClientStack.LindenUDP.Tests 35namespace OpenSim.Region.ClientStack.LindenUDP.Tests
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs
deleted file mode 100644
index 27b9e5b..0000000
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs
+++ /dev/null
@@ -1,170 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Net;
31using System.Net.Sockets;
32using Nini.Config;
33using OpenMetaverse.Packets;
34using OpenSim.Framework;
35
36namespace OpenSim.Region.ClientStack.LindenUDP.Tests
37{
38 /// <summary>
39 /// This class enables regression testing of the LLUDPServer by allowing us to intercept outgoing data.
40 /// </summary>
41 public class TestLLUDPServer : LLUDPServer
42 {
43 public List<Packet> PacketsSent { get; private set; }
44
45 public TestLLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
46 : base(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager)
47 {
48 PacketsSent = new List<Packet>();
49 }
50
51 public override void SendAckImmediate(IPEndPoint remoteEndpoint, PacketAckPacket ack)
52 {
53 PacketsSent.Add(ack);
54 }
55
56 public override void SendPacket(
57 LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method)
58 {
59 PacketsSent.Add(packet);
60 }
61
62 public void ClientOutgoingPacketHandler(IClientAPI client, bool resendUnacked, bool sendAcks, bool sendPing)
63 {
64 m_resendUnacked = resendUnacked;
65 m_sendAcks = sendAcks;
66 m_sendPing = sendPing;
67
68 ClientOutgoingPacketHandler(client);
69 }
70
71//// /// <summary>
72//// /// The chunks of data to pass to the LLUDPServer when it calls EndReceive
73//// /// </summary>
74//// protected Queue<ChunkSenderTuple> m_chunksToLoad = new Queue<ChunkSenderTuple>();
75//
76//// protected override void BeginReceive()
77//// {
78//// if (m_chunksToLoad.Count > 0 && m_chunksToLoad.Peek().BeginReceiveException)
79//// {
80//// ChunkSenderTuple tuple = m_chunksToLoad.Dequeue();
81//// reusedEpSender = tuple.Sender;
82//// throw new SocketException();
83//// }
84//// }
85//
86//// protected override bool EndReceive(out int numBytes, IAsyncResult result, ref EndPoint epSender)
87//// {
88//// numBytes = 0;
89////
90//// //m_log.Debug("Queue size " + m_chunksToLoad.Count);
91////
92//// if (m_chunksToLoad.Count <= 0)
93//// return false;
94////
95//// ChunkSenderTuple tuple = m_chunksToLoad.Dequeue();
96//// RecvBuffer = tuple.Data;
97//// numBytes = tuple.Data.Length;
98//// epSender = tuple.Sender;
99////
100//// return true;
101//// }
102//
103//// public override void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode)
104//// {
105//// // Don't do anything just yet
106//// }
107//
108// /// <summary>
109// /// Signal that this chunk should throw an exception on Socket.BeginReceive()
110// /// </summary>
111// /// <param name="epSender"></param>
112// public void LoadReceiveWithBeginException(EndPoint epSender)
113// {
114// ChunkSenderTuple tuple = new ChunkSenderTuple(epSender);
115// tuple.BeginReceiveException = true;
116// m_chunksToLoad.Enqueue(tuple);
117// }
118//
119// /// <summary>
120// /// Load some data to be received by the LLUDPServer on the next receive call
121// /// </summary>
122// /// <param name="data"></param>
123// /// <param name="epSender"></param>
124// public void LoadReceive(byte[] data, EndPoint epSender)
125// {
126// m_chunksToLoad.Enqueue(new ChunkSenderTuple(data, epSender));
127// }
128//
129// /// <summary>
130// /// Load a packet to be received by the LLUDPServer on the next receive call
131// /// </summary>
132// /// <param name="packet"></param>
133// public void LoadReceive(Packet packet, EndPoint epSender)
134// {
135// LoadReceive(packet.ToBytes(), epSender);
136// }
137//
138// /// <summary>
139// /// Calls the protected asynchronous result method. This fires out all data chunks currently queued for send
140// /// </summary>
141// /// <param name="result"></param>
142// public void ReceiveData(IAsyncResult result)
143// {
144// // Doesn't work the same way anymore
145//// while (m_chunksToLoad.Count > 0)
146//// OnReceivedData(result);
147// }
148 }
149
150 /// <summary>
151 /// Record the data and sender tuple
152 /// </summary>
153 public class ChunkSenderTuple
154 {
155 public byte[] Data;
156 public EndPoint Sender;
157 public bool BeginReceiveException;
158
159 public ChunkSenderTuple(byte[] data, EndPoint sender)
160 {
161 Data = data;
162 Sender = sender;
163 }
164
165 public ChunkSenderTuple(EndPoint sender)
166 {
167 Sender = sender;
168 }
169 }
170}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
new file mode 100644
index 0000000..3c82a78
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
@@ -0,0 +1,427 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using Nini.Config;
30using NUnit.Framework;
31using OpenMetaverse.Packets;
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Scenes;
34using OpenSim.Tests.Common;
35
36namespace OpenSim.Region.ClientStack.LindenUDP.Tests
37{
38 [TestFixture]
39 public class ThrottleTests : OpenSimTestCase
40 {
41 [TestFixtureSetUp]
42 public void FixtureInit()
43 {
44 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
45 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
46 }
47
48 [TestFixtureTearDown]
49 public void TearDown()
50 {
51 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
52 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
53 // tests really shouldn't).
54 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
55 }
56
57 [Test]
58 public void TestSetRequestDripRate()
59 {
60 TestHelpers.InMethod();
61
62 TokenBucket tb = new TokenBucket("tb", null, 5000, 0);
63 AssertRates(tb, 5000, 0, 5000, 0);
64
65 tb.RequestedDripRate = 4000;
66 AssertRates(tb, 4000, 0, 4000, 0);
67
68 tb.RequestedDripRate = 6000;
69 AssertRates(tb, 6000, 0, 6000, 0);
70 }
71
72 [Test]
73 public void TestSetRequestDripRateWithMax()
74 {
75 TestHelpers.InMethod();
76
77 TokenBucket tb = new TokenBucket("tb", null, 5000, 10000);
78 AssertRates(tb, 5000, 0, 5000, 10000);
79
80 tb.RequestedDripRate = 4000;
81 AssertRates(tb, 4000, 0, 4000, 10000);
82
83 tb.RequestedDripRate = 6000;
84 AssertRates(tb, 6000, 0, 6000, 10000);
85
86 tb.RequestedDripRate = 12000;
87 AssertRates(tb, 10000, 0, 10000, 10000);
88 }
89
90 [Test]
91 public void TestSetRequestDripRateWithChildren()
92 {
93 TestHelpers.InMethod();
94
95 TokenBucket tbParent = new TokenBucket("tbParent", null, 0, 0);
96 TokenBucket tbChild1 = new TokenBucket("tbChild1", tbParent, 3000, 0);
97 TokenBucket tbChild2 = new TokenBucket("tbChild2", tbParent, 5000, 0);
98
99 AssertRates(tbParent, 8000, 8000, 8000, 0);
100 AssertRates(tbChild1, 3000, 0, 3000, 0);
101 AssertRates(tbChild2, 5000, 0, 5000, 0);
102
103 // Test: Setting a parent request greater than total children requests.
104 tbParent.RequestedDripRate = 10000;
105
106 AssertRates(tbParent, 10000, 8000, 8000, 0);
107 AssertRates(tbChild1, 3000, 0, 3000, 0);
108 AssertRates(tbChild2, 5000, 0, 5000, 0);
109
110 // Test: Setting a parent request lower than total children requests.
111 tbParent.RequestedDripRate = 6000;
112
113 AssertRates(tbParent, 6000, 8000, 6000, 0);
114 AssertRates(tbChild1, 3000, 0, 6000 / 8 * 3, 0);
115 AssertRates(tbChild2, 5000, 0, 6000 / 8 * 5, 0);
116 }
117
118 private void AssertRates(
119 TokenBucket tb, double requestedDripRate, double totalDripRequest, double dripRate, double maxDripRate)
120 {
121 Assert.AreEqual((int)requestedDripRate, tb.RequestedDripRate, "Requested drip rate");
122 Assert.AreEqual((int)totalDripRequest, tb.TotalDripRequest, "Total drip request");
123 Assert.AreEqual((int)dripRate, tb.DripRate, "Drip rate");
124 Assert.AreEqual((int)maxDripRate, tb.MaxDripRate, "Max drip rate");
125 }
126
127 [Test]
128 public void TestClientThrottleSetNoLimit()
129 {
130 TestHelpers.InMethod();
131// TestHelpers.EnableLogging();
132
133 Scene scene = new SceneHelpers().SetupScene();
134 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
135
136 ScenePresence sp
137 = ClientStackHelpers.AddChildClient(
138 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
139
140 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
141
142 udpServer.Throttle.DebugLevel = 1;
143 udpClient.ThrottleDebugLevel = 1;
144
145 int resendBytes = 1000;
146 int landBytes = 2000;
147 int windBytes = 3000;
148 int cloudBytes = 4000;
149 int taskBytes = 5000;
150 int textureBytes = 6000;
151 int assetBytes = 7000;
152
153 SetThrottles(
154 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
155
156 // We expect this to be lower because of the minimum bound set by MTU
157 int totalBytes = LLUDPServer.MTU + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
158
159 AssertThrottles(
160 udpClient,
161 LLUDPServer.MTU, landBytes, windBytes, cloudBytes, taskBytes,
162 textureBytes, assetBytes, totalBytes, 0, 0);
163 }
164
165 [Test]
166 public void TestClientThrottleAdaptiveNoLimit()
167 {
168 TestHelpers.InMethod();
169// TestHelpers.EnableLogging();
170
171 Scene scene = new SceneHelpers().SetupScene();
172
173 IniConfigSource ics = new IniConfigSource();
174 IConfig config = ics.AddConfig("ClientStack.LindenUDP");
175 config.Set("enable_adaptive_throttles", true);
176 config.Set("adaptive_throttle_min_bps", 32000);
177
178 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene, ics);
179
180 ScenePresence sp
181 = ClientStackHelpers.AddChildClient(
182 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
183
184 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
185
186 udpServer.Throttle.DebugLevel = 1;
187 udpClient.ThrottleDebugLevel = 1;
188
189 // Total is 275000
190 int resendBytes = 5000; // this is set low to test the minimum throttle override
191 int landBytes = 20000;
192 int windBytes = 30000;
193 int cloudBytes = 40000;
194 int taskBytes = 50000;
195 int textureBytes = 60000;
196 int assetBytes = 70000;
197 int totalBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
198
199 SetThrottles(
200 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
201
202 // Ratio of current adaptive drip rate to requested bytes, minimum rate is 32000
203 double commitRatio = 32000.0 / totalBytes;
204
205 AssertThrottles(
206 udpClient,
207 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
208 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
209
210 // Test an increase in target throttle, ack of 20 packets adds 20 * LLUDPServer.MTU bytes
211 // to the throttle, recompute commitratio from those numbers
212 udpClient.FlowThrottle.AcknowledgePackets(20);
213 commitRatio = (32000.0 + 20.0 * LLUDPServer.MTU) / totalBytes;
214
215 AssertThrottles(
216 udpClient,
217 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
218 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
219
220 // Test a decrease in target throttle, adaptive throttle should cut the rate by 50% with a floor
221 // set by the minimum adaptive rate
222 udpClient.FlowThrottle.ExpirePackets(1);
223 commitRatio = (32000.0 + (20.0 * LLUDPServer.MTU)/Math.Pow(2,1)) / totalBytes;
224
225 AssertThrottles(
226 udpClient,
227 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
228 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
229 }
230
231 /// <summary>
232 /// Test throttle setttings where max client throttle has been limited server side.
233 /// </summary>
234 [Test]
235 public void TestSingleClientThrottleRegionLimited()
236 {
237 TestHelpers.InMethod();
238 // TestHelpers.EnableLogging();
239
240 int resendBytes = 6000;
241 int landBytes = 8000;
242 int windBytes = 10000;
243 int cloudBytes = 12000;
244 int taskBytes = 14000;
245 int textureBytes = 16000;
246 int assetBytes = 18000;
247 int totalBytes
248 = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2);
249
250 Scene scene = new SceneHelpers().SetupScene();
251 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
252 udpServer.Throttle.RequestedDripRate = totalBytes;
253
254 ScenePresence sp1
255 = ClientStackHelpers.AddChildClient(
256 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
257
258 LLUDPClient udpClient1 = ((LLClientView)sp1.ControllingClient).UDPClient;
259
260 SetThrottles(
261 udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
262
263 AssertThrottles(
264 udpClient1,
265 resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2,
266 textureBytes / 2, assetBytes / 2, totalBytes, 0, 0);
267
268 // Test: Now add another client
269 ScenePresence sp2
270 = ClientStackHelpers.AddChildClient(
271 scene, udpServer, TestHelpers.ParseTail(0x10), TestHelpers.ParseTail(0x20), 123457);
272
273 LLUDPClient udpClient2 = ((LLClientView)sp2.ControllingClient).UDPClient;
274 // udpClient.ThrottleDebugLevel = 1;
275
276 SetThrottles(
277 udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
278
279 AssertThrottles(
280 udpClient1,
281 resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4,
282 textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0);
283
284 AssertThrottles(
285 udpClient2,
286 resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4,
287 textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0);
288 }
289
290 /// <summary>
291 /// Test throttle setttings where max client throttle has been limited server side.
292 /// </summary>
293 [Test]
294 public void TestClientThrottlePerClientLimited()
295 {
296 TestHelpers.InMethod();
297 // TestHelpers.EnableLogging();
298
299 int resendBytes = 4000;
300 int landBytes = 6000;
301 int windBytes = 8000;
302 int cloudBytes = 10000;
303 int taskBytes = 12000;
304 int textureBytes = 14000;
305 int assetBytes = 16000;
306 int totalBytes
307 = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2);
308
309 Scene scene = new SceneHelpers().SetupScene();
310 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
311 udpServer.ThrottleRates.Total = totalBytes;
312
313 ScenePresence sp
314 = ClientStackHelpers.AddChildClient(
315 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
316
317 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
318 // udpClient.ThrottleDebugLevel = 1;
319
320 SetThrottles(
321 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
322
323 AssertThrottles(
324 udpClient,
325 resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2,
326 textureBytes / 2, assetBytes / 2, totalBytes, 0, totalBytes);
327 }
328
329 [Test]
330 public void TestClientThrottlePerClientAndRegionLimited()
331 {
332 TestHelpers.InMethod();
333 //TestHelpers.EnableLogging();
334
335 int resendBytes = 4000;
336 int landBytes = 6000;
337 int windBytes = 8000;
338 int cloudBytes = 10000;
339 int taskBytes = 12000;
340 int textureBytes = 14000;
341 int assetBytes = 16000;
342
343 // current total 70000
344 int totalBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
345
346 Scene scene = new SceneHelpers().SetupScene();
347 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
348 udpServer.ThrottleRates.Total = (int)(totalBytes * 1.1);
349 udpServer.Throttle.RequestedDripRate = (int)(totalBytes * 1.5);
350
351 ScenePresence sp1
352 = ClientStackHelpers.AddChildClient(
353 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
354
355 LLUDPClient udpClient1 = ((LLClientView)sp1.ControllingClient).UDPClient;
356 udpClient1.ThrottleDebugLevel = 1;
357
358 SetThrottles(
359 udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
360
361 AssertThrottles(
362 udpClient1,
363 resendBytes, landBytes, windBytes, cloudBytes, taskBytes,
364 textureBytes, assetBytes, totalBytes, 0, totalBytes * 1.1);
365
366 // Now add another client
367 ScenePresence sp2
368 = ClientStackHelpers.AddChildClient(
369 scene, udpServer, TestHelpers.ParseTail(0x10), TestHelpers.ParseTail(0x20), 123457);
370
371 LLUDPClient udpClient2 = ((LLClientView)sp2.ControllingClient).UDPClient;
372 udpClient2.ThrottleDebugLevel = 1;
373
374 SetThrottles(
375 udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
376
377 AssertThrottles(
378 udpClient1,
379 resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75,
380 textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1);
381
382 AssertThrottles(
383 udpClient2,
384 resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75,
385 textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1);
386 }
387
388 private void AssertThrottles(
389 LLUDPClient udpClient,
390 double resendBytes, double landBytes, double windBytes, double cloudBytes, double taskBytes, double textureBytes, double assetBytes,
391 double totalBytes, double targetBytes, double maxBytes)
392 {
393 ClientInfo ci = udpClient.GetClientInfo();
394
395// Console.WriteLine(
396// "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}",
397// ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle);
398
399 Assert.AreEqual((int)resendBytes, ci.resendThrottle, "Resend");
400 Assert.AreEqual((int)landBytes, ci.landThrottle, "Land");
401 Assert.AreEqual((int)windBytes, ci.windThrottle, "Wind");
402 Assert.AreEqual((int)cloudBytes, ci.cloudThrottle, "Cloud");
403 Assert.AreEqual((int)taskBytes, ci.taskThrottle, "Task");
404 Assert.AreEqual((int)textureBytes, ci.textureThrottle, "Texture");
405 Assert.AreEqual((int)assetBytes, ci.assetThrottle, "Asset");
406 Assert.AreEqual((int)totalBytes, ci.totalThrottle, "Total");
407 Assert.AreEqual((int)targetBytes, ci.targetThrottle, "Target");
408 Assert.AreEqual((int)maxBytes, ci.maxThrottle, "Max");
409 }
410
411 private void SetThrottles(
412 LLUDPClient udpClient, int resendBytes, int landBytes, int windBytes, int cloudBytes, int taskBytes, int textureBytes, int assetBytes)
413 {
414 byte[] throttles = new byte[28];
415
416 Array.Copy(BitConverter.GetBytes((float)resendBytes * 8), 0, throttles, 0, 4);
417 Array.Copy(BitConverter.GetBytes((float)landBytes * 8), 0, throttles, 4, 4);
418 Array.Copy(BitConverter.GetBytes((float)windBytes * 8), 0, throttles, 8, 4);
419 Array.Copy(BitConverter.GetBytes((float)cloudBytes * 8), 0, throttles, 12, 4);
420 Array.Copy(BitConverter.GetBytes((float)taskBytes * 8), 0, throttles, 16, 4);
421 Array.Copy(BitConverter.GetBytes((float)textureBytes * 8), 0, throttles, 20, 4);
422 Array.Copy(BitConverter.GetBytes((float)assetBytes * 8), 0, throttles, 24, 4);
423
424 udpClient.SetThrottles(throttles);
425 }
426 }
427} \ No newline at end of file