diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 974 |
1 files changed, 700 insertions, 274 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index a7628d2..4528714 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -40,8 +40,9 @@ using OpenSim.Framework; | |||
40 | using OpenSim.Framework.Console; | 40 | using OpenSim.Framework.Console; |
41 | using OpenSim.Framework.Monitoring; | 41 | using OpenSim.Framework.Monitoring; |
42 | using OpenSim.Region.Framework.Scenes; | 42 | using OpenSim.Region.Framework.Scenes; |
43 | using OpenSim.Region.Framework.Interfaces; | ||
43 | using OpenMetaverse; | 44 | using OpenMetaverse; |
44 | 45 | using Mono.Addins; | |
45 | using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket; | 46 | using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket; |
46 | 47 | ||
47 | namespace OpenSim.Region.ClientStack.LindenUDP | 48 | namespace OpenSim.Region.ClientStack.LindenUDP |
@@ -49,22 +50,58 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
49 | /// <summary> | 50 | /// <summary> |
50 | /// A shim around LLUDPServer that implements the IClientNetworkServer interface | 51 | /// A shim around LLUDPServer that implements the IClientNetworkServer interface |
51 | /// </summary> | 52 | /// </summary> |
52 | public sealed class LLUDPServerShim : IClientNetworkServer | 53 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LLUDPServerShim")] |
54 | public sealed class LLUDPServerShim : INonSharedRegionModule | ||
53 | { | 55 | { |
56 | private bool m_Enabled = true; | ||
57 | private IConfigSource m_Config; | ||
54 | LLUDPServer m_udpServer; | 58 | LLUDPServer m_udpServer; |
55 | 59 | ||
56 | public LLUDPServerShim() | 60 | #region INonSharedRegionModule |
61 | public string Name | ||
57 | { | 62 | { |
63 | get { return "LLUDPServerShim"; } | ||
58 | } | 64 | } |
59 | 65 | ||
60 | public void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) | 66 | public Type ReplaceableInterface |
61 | { | 67 | { |
62 | m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); | 68 | get { return null; } |
63 | } | 69 | } |
64 | 70 | ||
65 | public void NetworkStop() | 71 | public void Initialise(IConfigSource source) |
66 | { | 72 | { |
67 | m_udpServer.Stop(); | 73 | m_Config = source; |
74 | } | ||
75 | |||
76 | public void Close() | ||
77 | { | ||
78 | } | ||
79 | |||
80 | public void AddRegion(Scene scene) | ||
81 | { | ||
82 | uint port = (uint)scene.RegionInfo.InternalEndPoint.Port; | ||
83 | |||
84 | IPAddress listenIP = scene.RegionInfo.InternalEndPoint.Address; | ||
85 | Initialise(listenIP, ref port, scene.RegionInfo.ProxyOffset, scene.RegionInfo.m_allow_alternate_ports, m_Config, scene.AuthenticateHandler); | ||
86 | scene.RegionInfo.InternalEndPoint.Port = (int)port; | ||
87 | |||
88 | AddScene(scene); | ||
89 | } | ||
90 | |||
91 | public void RemoveRegion(Scene scene) | ||
92 | { | ||
93 | Stop(); | ||
94 | } | ||
95 | |||
96 | public void RegionLoaded(Scene scene) | ||
97 | { | ||
98 | Start(); | ||
99 | } | ||
100 | #endregion | ||
101 | |||
102 | public void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) | ||
103 | { | ||
104 | m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); | ||
68 | } | 105 | } |
69 | 106 | ||
70 | public void AddScene(IScene scene) | 107 | public void AddScene(IScene scene) |
@@ -73,9 +110,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
73 | 110 | ||
74 | StatsManager.RegisterStat( | 111 | StatsManager.RegisterStat( |
75 | new Stat( | 112 | new Stat( |
113 | "ClientLogoutsDueToNoReceives", | ||
114 | "Number of times a client has been logged out because no packets were received before the timeout.", | ||
115 | "", | ||
116 | "", | ||
117 | "clientstack", | ||
118 | scene.Name, | ||
119 | StatType.Pull, | ||
120 | MeasuresOfInterest.None, | ||
121 | stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives, | ||
122 | StatVerbosity.Debug)); | ||
123 | |||
124 | StatsManager.RegisterStat( | ||
125 | new Stat( | ||
126 | "IncomingUDPReceivesCount", | ||
127 | "Number of UDP receives performed", | ||
128 | "", | ||
129 | "", | ||
130 | "clientstack", | ||
131 | scene.Name, | ||
132 | StatType.Pull, | ||
133 | MeasuresOfInterest.AverageChangeOverTime, | ||
134 | stat => stat.Value = m_udpServer.UdpReceives, | ||
135 | StatVerbosity.Debug)); | ||
136 | |||
137 | StatsManager.RegisterStat( | ||
138 | new Stat( | ||
76 | "IncomingPacketsProcessedCount", | 139 | "IncomingPacketsProcessedCount", |
77 | "Number of inbound UDP packets processed", | 140 | "Number of inbound LL protocol packets processed", |
78 | "Number of inbound UDP packets processed", | 141 | "", |
79 | "", | 142 | "", |
80 | "clientstack", | 143 | "clientstack", |
81 | scene.Name, | 144 | scene.Name, |
@@ -83,6 +146,86 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
83 | MeasuresOfInterest.AverageChangeOverTime, | 146 | MeasuresOfInterest.AverageChangeOverTime, |
84 | stat => stat.Value = m_udpServer.IncomingPacketsProcessed, | 147 | stat => stat.Value = m_udpServer.IncomingPacketsProcessed, |
85 | StatVerbosity.Debug)); | 148 | StatVerbosity.Debug)); |
149 | |||
150 | StatsManager.RegisterStat( | ||
151 | new Stat( | ||
152 | "IncomingPacketsMalformedCount", | ||
153 | "Number of inbound UDP packets that could not be recognized as LL protocol packets.", | ||
154 | "", | ||
155 | "", | ||
156 | "clientstack", | ||
157 | scene.Name, | ||
158 | StatType.Pull, | ||
159 | MeasuresOfInterest.AverageChangeOverTime, | ||
160 | stat => stat.Value = m_udpServer.IncomingMalformedPacketCount, | ||
161 | StatVerbosity.Info)); | ||
162 | |||
163 | StatsManager.RegisterStat( | ||
164 | new Stat( | ||
165 | "IncomingPacketsOrphanedCount", | ||
166 | "Number of inbound packets that were not initial connections packets and could not be associated with a viewer.", | ||
167 | "", | ||
168 | "", | ||
169 | "clientstack", | ||
170 | scene.Name, | ||
171 | StatType.Pull, | ||
172 | MeasuresOfInterest.AverageChangeOverTime, | ||
173 | stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount, | ||
174 | StatVerbosity.Info)); | ||
175 | |||
176 | StatsManager.RegisterStat( | ||
177 | new Stat( | ||
178 | "IncomingPacketsResentCount", | ||
179 | "Number of inbound packets that clients indicate are resends.", | ||
180 | "", | ||
181 | "", | ||
182 | "clientstack", | ||
183 | scene.Name, | ||
184 | StatType.Pull, | ||
185 | MeasuresOfInterest.AverageChangeOverTime, | ||
186 | stat => stat.Value = m_udpServer.IncomingPacketsResentCount, | ||
187 | StatVerbosity.Debug)); | ||
188 | |||
189 | StatsManager.RegisterStat( | ||
190 | new Stat( | ||
191 | "OutgoingUDPSendsCount", | ||
192 | "Number of UDP sends performed", | ||
193 | "", | ||
194 | "", | ||
195 | "clientstack", | ||
196 | scene.Name, | ||
197 | StatType.Pull, | ||
198 | MeasuresOfInterest.AverageChangeOverTime, | ||
199 | stat => stat.Value = m_udpServer.UdpSends, | ||
200 | StatVerbosity.Debug)); | ||
201 | |||
202 | StatsManager.RegisterStat( | ||
203 | new Stat( | ||
204 | "OutgoingPacketsResentCount", | ||
205 | "Number of packets resent because a client did not acknowledge receipt", | ||
206 | "", | ||
207 | "", | ||
208 | "clientstack", | ||
209 | scene.Name, | ||
210 | StatType.Pull, | ||
211 | MeasuresOfInterest.AverageChangeOverTime, | ||
212 | stat => stat.Value = m_udpServer.PacketsResentCount, | ||
213 | StatVerbosity.Debug)); | ||
214 | |||
215 | StatsManager.RegisterStat( | ||
216 | new Stat( | ||
217 | "AverageUDPProcessTime", | ||
218 | "Average number of milliseconds taken to process each incoming UDP packet in a sample.", | ||
219 | "This is for initial receive processing which is separate from the later client LL packet processing stage.", | ||
220 | "ms", | ||
221 | "clientstack", | ||
222 | scene.Name, | ||
223 | StatType.Pull, | ||
224 | MeasuresOfInterest.None, | ||
225 | stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod, | ||
226 | // stat => | ||
227 | // stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod, 7), | ||
228 | StatVerbosity.Debug)); | ||
86 | } | 229 | } |
87 | 230 | ||
88 | public bool HandlesRegion(Location x) | 231 | public bool HandlesRegion(Location x) |
@@ -99,6 +242,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
99 | { | 242 | { |
100 | m_udpServer.Stop(); | 243 | m_udpServer.Stop(); |
101 | } | 244 | } |
245 | |||
102 | } | 246 | } |
103 | 247 | ||
104 | /// <summary> | 248 | /// <summary> |
@@ -107,10 +251,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
107 | /// </summary> | 251 | /// </summary> |
108 | public class LLUDPServer : OpenSimUDPBase | 252 | public class LLUDPServer : OpenSimUDPBase |
109 | { | 253 | { |
254 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
255 | |||
110 | /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> | 256 | /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> |
111 | public const int MTU = 1400; | 257 | public const int MTU = 1400; |
112 | 258 | ||
113 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 259 | /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary> |
260 | public int ClientLogoutsDueToNoReceives { get; private set; } | ||
261 | |||
262 | /// <summary> | ||
263 | /// Default packet debug level given to new clients | ||
264 | /// </summary> | ||
265 | public int DefaultClientPacketDebugLevel { get; set; } | ||
266 | |||
267 | /// <summary> | ||
268 | /// If set then all inbound agent updates are discarded. For debugging purposes. | ||
269 | /// discard agent update. | ||
270 | /// </summary> | ||
271 | public bool DiscardInboundAgentUpdates { get; set; } | ||
114 | 272 | ||
115 | /// <summary>The measured resolution of Environment.TickCount</summary> | 273 | /// <summary>The measured resolution of Environment.TickCount</summary> |
116 | public readonly float TickCountResolution; | 274 | public readonly float TickCountResolution; |
@@ -128,19 +286,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
128 | /// <summary>Incoming packets that are awaiting handling</summary> | 286 | /// <summary>Incoming packets that are awaiting handling</summary> |
129 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); | 287 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); |
130 | 288 | ||
131 | /// <summary></summary> | ||
132 | //private UDPClientCollection m_clients = new UDPClientCollection(); | ||
133 | /// <summary>Bandwidth throttle for this UDP server</summary> | 289 | /// <summary>Bandwidth throttle for this UDP server</summary> |
134 | protected TokenBucket m_throttle; | 290 | public TokenBucket Throttle { get; private set; } |
135 | 291 | ||
136 | /// <summary>Bandwidth throttle rates for this UDP server</summary> | 292 | /// <summary>Per client throttle rates enforced by this server</summary> |
293 | /// <remarks> | ||
294 | /// If the total rate is non-zero, then this is the maximum total throttle setting that any client can ever have. | ||
295 | /// The other rates (resend, asset, etc.) are the defaults for a new client and can be changed (and usually | ||
296 | /// do get changed immediately). They do not need to sum to the total. | ||
297 | /// </remarks> | ||
137 | public ThrottleRates ThrottleRates { get; private set; } | 298 | public ThrottleRates ThrottleRates { get; private set; } |
138 | 299 | ||
139 | /// <summary>Manages authentication for agent circuits</summary> | 300 | /// <summary>Manages authentication for agent circuits</summary> |
140 | private AgentCircuitManager m_circuitManager; | 301 | private AgentCircuitManager m_circuitManager; |
141 | 302 | ||
142 | /// <summary>Reference to the scene this UDP server is attached to</summary> | 303 | /// <summary>Reference to the scene this UDP server is attached to</summary> |
143 | protected Scene m_scene; | 304 | public Scene Scene { get; private set; } |
144 | 305 | ||
145 | /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> | 306 | /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> |
146 | private Location m_location; | 307 | private Location m_location; |
@@ -181,6 +342,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
181 | /// <summary>Flag to signal when clients should send pings</summary> | 342 | /// <summary>Flag to signal when clients should send pings</summary> |
182 | protected bool m_sendPing; | 343 | protected bool m_sendPing; |
183 | 344 | ||
345 | /// <summary> | ||
346 | /// Event used to signal when queued packets are available for sending. | ||
347 | /// </summary> | ||
348 | /// <remarks> | ||
349 | /// This allows the outbound loop to only operate when there is data to send rather than continuously polling. | ||
350 | /// Some data is sent immediately and not queued. That data would not trigger this event. | ||
351 | /// </remarks> | ||
352 | private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); | ||
353 | |||
184 | private Pool<IncomingPacket> m_incomingPacketPool; | 354 | private Pool<IncomingPacket> m_incomingPacketPool; |
185 | 355 | ||
186 | /// <summary> | 356 | /// <summary> |
@@ -201,7 +371,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
201 | 371 | ||
202 | public Socket Server { get { return null; } } | 372 | public Socket Server { get { return null; } } |
203 | 373 | ||
204 | private int m_malformedCount = 0; // Guard against a spamming attack | 374 | /// <summary> |
375 | /// Record how many packets have been resent | ||
376 | /// </summary> | ||
377 | internal int PacketsResentCount { get; set; } | ||
378 | |||
379 | /// <summary> | ||
380 | /// Record how many packets have been sent | ||
381 | /// </summary> | ||
382 | internal int PacketsSentCount { get; set; } | ||
383 | |||
384 | /// <summary> | ||
385 | /// Record how many incoming packets are indicated as resends by clients. | ||
386 | /// </summary> | ||
387 | internal int IncomingPacketsResentCount { get; set; } | ||
388 | |||
389 | /// <summary> | ||
390 | /// Record how many inbound packets could not be recognized as LLUDP packets. | ||
391 | /// </summary> | ||
392 | public int IncomingMalformedPacketCount { get; private set; } | ||
393 | |||
394 | /// <summary> | ||
395 | /// Record how many inbound packets could not be associated with a simulator circuit. | ||
396 | /// </summary> | ||
397 | public int IncomingOrphanedPacketCount { get; private set; } | ||
205 | 398 | ||
206 | /// <summary> | 399 | /// <summary> |
207 | /// Record current outgoing client for monitoring purposes. | 400 | /// Record current outgoing client for monitoring purposes. |
@@ -213,6 +406,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
213 | /// </summary> | 406 | /// </summary> |
214 | private IClientAPI m_currentIncomingClient; | 407 | private IClientAPI m_currentIncomingClient; |
215 | 408 | ||
409 | /// <summary> | ||
410 | /// Queue some low priority but potentially high volume async requests so that they don't overwhelm available | ||
411 | /// threadpool threads. | ||
412 | /// </summary> | ||
413 | public JobEngine IpahEngine { get; private set; } | ||
414 | |||
415 | /// <summary> | ||
416 | /// Run queue empty processing within a single persistent thread. | ||
417 | /// </summary> | ||
418 | /// <remarks> | ||
419 | /// This is the alternative to having every | ||
420 | /// connection schedule its own job in the threadpool which causes performance problems when there are many | ||
421 | /// connections. | ||
422 | /// </remarks> | ||
423 | public JobEngine OqrEngine { get; private set; } | ||
424 | |||
216 | public LLUDPServer( | 425 | public LLUDPServer( |
217 | IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, | 426 | IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, |
218 | IConfigSource configSource, AgentCircuitManager circuitManager) | 427 | IConfigSource configSource, AgentCircuitManager circuitManager) |
@@ -278,27 +487,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
278 | m_shouldCollectStats = false; | 487 | m_shouldCollectStats = false; |
279 | if (config != null) | 488 | if (config != null) |
280 | { | 489 | { |
281 | if (config.Contains("enabled") && config.GetBoolean("enabled")) | 490 | m_shouldCollectStats = config.GetBoolean("Enabled", false); |
282 | { | 491 | binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("packet_headers_period_seconds", 300)); |
283 | if (config.Contains("collect_packet_headers")) | 492 | binStatsDir = config.GetString("stats_dir", "."); |
284 | m_shouldCollectStats = config.GetBoolean("collect_packet_headers"); | 493 | m_aggregatedBWStats = config.GetBoolean("aggregatedBWStats", false); |
285 | if (config.Contains("packet_headers_period_seconds")) | 494 | } |
286 | { | 495 | #endregion BinaryStats |
287 | binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("region_stats_period_seconds")); | 496 | |
288 | } | 497 | // FIXME: Can't add info here because don't know scene yet. |
289 | if (config.Contains("stats_dir")) | 498 | // m_throttle |
290 | { | 499 | // = new TokenBucket( |
291 | binStatsDir = config.GetString("stats_dir"); | 500 | // string.Format("server throttle bucket for {0}", Scene.Name), null, sceneThrottleBps); |
292 | } | 501 | |
293 | } | 502 | Throttle = new TokenBucket("server throttle bucket", null, 0, sceneThrottleBps); |
294 | else | 503 | |
295 | { | ||
296 | m_shouldCollectStats = false; | ||
297 | } | ||
298 | } | ||
299 | #endregion BinaryStats | ||
300 | |||
301 | m_throttle = new TokenBucket(null, sceneThrottleBps); | ||
302 | ThrottleRates = new ThrottleRates(configSource); | 504 | ThrottleRates = new ThrottleRates(configSource); |
303 | 505 | ||
304 | if (usePools) | 506 | if (usePools) |
@@ -309,11 +511,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
309 | { | 511 | { |
310 | StartInbound(); | 512 | StartInbound(); |
311 | StartOutbound(); | 513 | StartOutbound(); |
514 | IpahEngine.Start(); | ||
515 | OqrEngine.Start(); | ||
312 | 516 | ||
313 | m_elapsedMSSinceLastStatReport = Environment.TickCount; | 517 | m_elapsedMSSinceLastStatReport = Environment.TickCount; |
314 | } | 518 | } |
315 | 519 | ||
316 | private void StartInbound() | 520 | public void StartInbound() |
317 | { | 521 | { |
318 | m_log.InfoFormat( | 522 | m_log.InfoFormat( |
319 | "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}", | 523 | "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}", |
@@ -322,9 +526,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
322 | base.StartInbound(m_recvBufferSize, m_asyncPacketHandling); | 526 | base.StartInbound(m_recvBufferSize, m_asyncPacketHandling); |
323 | 527 | ||
324 | // This thread will process the packets received that are placed on the packetInbox | 528 | // This thread will process the packets received that are placed on the packetInbox |
325 | Watchdog.StartThread( | 529 | WorkManager.StartThread( |
326 | IncomingPacketHandler, | 530 | IncomingPacketHandler, |
327 | string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName), | 531 | string.Format("Incoming Packets ({0})", Scene.Name), |
328 | ThreadPriority.Normal, | 532 | ThreadPriority.Normal, |
329 | false, | 533 | false, |
330 | true, | 534 | true, |
@@ -332,15 +536,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
332 | Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); | 536 | Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); |
333 | } | 537 | } |
334 | 538 | ||
335 | private new void StartOutbound() | 539 | public override void StartOutbound() |
336 | { | 540 | { |
337 | m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server"); | 541 | m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server"); |
338 | 542 | ||
339 | base.StartOutbound(); | 543 | base.StartOutbound(); |
340 | 544 | ||
341 | Watchdog.StartThread( | 545 | WorkManager.StartThread( |
342 | OutgoingPacketHandler, | 546 | OutgoingPacketHandler, |
343 | string.Format("Outgoing Packets ({0})", m_scene.RegionInfo.RegionName), | 547 | string.Format("Outgoing Packets ({0})", Scene.Name), |
344 | ThreadPriority.Normal, | 548 | ThreadPriority.Normal, |
345 | false, | 549 | false, |
346 | true, | 550 | true, |
@@ -350,12 +554,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
350 | 554 | ||
351 | public void Stop() | 555 | public void Stop() |
352 | { | 556 | { |
353 | m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); | 557 | m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name); |
354 | base.StopOutbound(); | 558 | base.StopOutbound(); |
355 | base.StopInbound(); | 559 | base.StopInbound(); |
560 | IpahEngine.Stop(); | ||
561 | OqrEngine.Stop(); | ||
356 | } | 562 | } |
357 | 563 | ||
358 | protected override bool EnablePools() | 564 | public override bool EnablePools() |
359 | { | 565 | { |
360 | if (!UsePools) | 566 | if (!UsePools) |
361 | { | 567 | { |
@@ -369,7 +575,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
369 | return false; | 575 | return false; |
370 | } | 576 | } |
371 | 577 | ||
372 | protected override bool DisablePools() | 578 | public override bool DisablePools() |
373 | { | 579 | { |
374 | if (UsePools) | 580 | if (UsePools) |
375 | { | 581 | { |
@@ -389,7 +595,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
389 | /// This is a seperate method so that it can be called once we have an m_scene to distinguish different scene | 595 | /// This is a seperate method so that it can be called once we have an m_scene to distinguish different scene |
390 | /// stats. | 596 | /// stats. |
391 | /// </summary> | 597 | /// </summary> |
392 | private void EnablePoolStats() | 598 | protected internal void EnablePoolStats() |
393 | { | 599 | { |
394 | m_poolCountStat | 600 | m_poolCountStat |
395 | = new Stat( | 601 | = new Stat( |
@@ -398,7 +604,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
398 | "The number of objects currently stored within the UDPPacketBuffer pool", | 604 | "The number of objects currently stored within the UDPPacketBuffer pool", |
399 | "", | 605 | "", |
400 | "clientstack", | 606 | "clientstack", |
401 | m_scene.Name, | 607 | Scene.Name, |
402 | StatType.Pull, | 608 | StatType.Pull, |
403 | stat => stat.Value = Pool.Count, | 609 | stat => stat.Value = Pool.Count, |
404 | StatVerbosity.Debug); | 610 | StatVerbosity.Debug); |
@@ -412,7 +618,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
412 | "The number of objects currently stored within the incoming packet pool", | 618 | "The number of objects currently stored within the incoming packet pool", |
413 | "", | 619 | "", |
414 | "clientstack", | 620 | "clientstack", |
415 | m_scene.Name, | 621 | Scene.Name, |
416 | StatType.Pull, | 622 | StatType.Pull, |
417 | stat => stat.Value = m_incomingPacketPool.Count, | 623 | stat => stat.Value = m_incomingPacketPool.Count, |
418 | StatVerbosity.Debug); | 624 | StatVerbosity.Debug); |
@@ -423,7 +629,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
423 | /// <summary> | 629 | /// <summary> |
424 | /// Disables pool stats. | 630 | /// Disables pool stats. |
425 | /// </summary> | 631 | /// </summary> |
426 | private void DisablePoolStats() | 632 | protected internal void DisablePoolStats() |
427 | { | 633 | { |
428 | StatsManager.DeregisterStat(m_poolCountStat); | 634 | StatsManager.DeregisterStat(m_poolCountStat); |
429 | m_poolCountStat = null; | 635 | m_poolCountStat = null; |
@@ -456,7 +662,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
456 | 662 | ||
457 | public void AddScene(IScene scene) | 663 | public void AddScene(IScene scene) |
458 | { | 664 | { |
459 | if (m_scene != null) | 665 | if (Scene != null) |
460 | { | 666 | { |
461 | m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene"); | 667 | m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene"); |
462 | return; | 668 | return; |
@@ -468,8 +674,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
468 | return; | 674 | return; |
469 | } | 675 | } |
470 | 676 | ||
471 | m_scene = (Scene)scene; | 677 | Scene = (Scene)scene; |
472 | m_location = new Location(m_scene.RegionInfo.RegionHandle); | 678 | m_location = new Location(Scene.RegionInfo.RegionHandle); |
679 | |||
680 | IpahEngine | ||
681 | = new JobEngine( | ||
682 | string.Format("Incoming Packet Async Handling Engine ({0})", Scene.Name), | ||
683 | "INCOMING PACKET ASYNC HANDLING ENGINE"); | ||
684 | |||
685 | OqrEngine | ||
686 | = new JobEngine( | ||
687 | string.Format("Outgoing Queue Refill Engine ({0})", Scene.Name), | ||
688 | "OUTGOING QUEUE REFILL ENGINE"); | ||
689 | |||
690 | StatsManager.RegisterStat( | ||
691 | new Stat( | ||
692 | "InboxPacketsCount", | ||
693 | "Number of LL protocol packets waiting for the second stage of processing after initial receive.", | ||
694 | "Number of LL protocol packets waiting for the second stage of processing after initial receive.", | ||
695 | "", | ||
696 | "clientstack", | ||
697 | scene.Name, | ||
698 | StatType.Pull, | ||
699 | MeasuresOfInterest.AverageChangeOverTime, | ||
700 | stat => stat.Value = packetInbox.Count, | ||
701 | StatVerbosity.Debug)); | ||
473 | 702 | ||
474 | // XXX: These stats are also pool stats but we register them separately since they are currently not | 703 | // XXX: These stats are also pool stats but we register them separately since they are currently not |
475 | // turned on and off by EnablePools()/DisablePools() | 704 | // turned on and off by EnablePools()/DisablePools() |
@@ -479,7 +708,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
479 | "Packets reused", | 708 | "Packets reused", |
480 | "Number of packets reused out of all requests to the packet pool", | 709 | "Number of packets reused out of all requests to the packet pool", |
481 | "clientstack", | 710 | "clientstack", |
482 | m_scene.Name, | 711 | Scene.Name, |
483 | StatType.Pull, | 712 | StatType.Pull, |
484 | stat => | 713 | stat => |
485 | { PercentageStat pstat = (PercentageStat)stat; | 714 | { PercentageStat pstat = (PercentageStat)stat; |
@@ -493,7 +722,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
493 | "Packet data blocks reused", | 722 | "Packet data blocks reused", |
494 | "Number of data blocks reused out of all requests to the packet pool", | 723 | "Number of data blocks reused out of all requests to the packet pool", |
495 | "clientstack", | 724 | "clientstack", |
496 | m_scene.Name, | 725 | Scene.Name, |
497 | StatType.Pull, | 726 | StatType.Pull, |
498 | stat => | 727 | stat => |
499 | { PercentageStat pstat = (PercentageStat)stat; | 728 | { PercentageStat pstat = (PercentageStat)stat; |
@@ -508,7 +737,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
508 | "The number of objects currently stored within the packet pool", | 737 | "The number of objects currently stored within the packet pool", |
509 | "", | 738 | "", |
510 | "clientstack", | 739 | "clientstack", |
511 | m_scene.Name, | 740 | Scene.Name, |
512 | StatType.Pull, | 741 | StatType.Pull, |
513 | stat => stat.Value = PacketPool.Instance.PacketsPooled, | 742 | stat => stat.Value = PacketPool.Instance.PacketsPooled, |
514 | StatVerbosity.Debug)); | 743 | StatVerbosity.Debug)); |
@@ -520,132 +749,57 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
520 | "The number of objects currently stored within the packet data block pool", | 749 | "The number of objects currently stored within the packet data block pool", |
521 | "", | 750 | "", |
522 | "clientstack", | 751 | "clientstack", |
523 | m_scene.Name, | 752 | Scene.Name, |
524 | StatType.Pull, | 753 | StatType.Pull, |
525 | stat => stat.Value = PacketPool.Instance.BlocksPooled, | 754 | stat => stat.Value = PacketPool.Instance.BlocksPooled, |
526 | StatVerbosity.Debug)); | 755 | StatVerbosity.Debug)); |
756 | |||
757 | StatsManager.RegisterStat( | ||
758 | new Stat( | ||
759 | "OutgoingPacketsQueuedCount", | ||
760 | "Packets queued for outgoing send", | ||
761 | "Number of queued outgoing packets across all connections", | ||
762 | "", | ||
763 | "clientstack", | ||
764 | Scene.Name, | ||
765 | StatType.Pull, | ||
766 | MeasuresOfInterest.AverageChangeOverTime, | ||
767 | stat => stat.Value = GetTotalQueuedOutgoingPackets(), | ||
768 | StatVerbosity.Info)); | ||
769 | |||
770 | StatsManager.RegisterStat( | ||
771 | new Stat( | ||
772 | "IncomingPacketAsyncRequestsWaiting", | ||
773 | "Number of incoming packets waiting for async processing in engine.", | ||
774 | "", | ||
775 | "", | ||
776 | "clientstack", | ||
777 | Scene.Name, | ||
778 | StatType.Pull, | ||
779 | MeasuresOfInterest.None, | ||
780 | stat => stat.Value = IpahEngine.JobsWaiting, | ||
781 | StatVerbosity.Debug)); | ||
782 | |||
783 | StatsManager.RegisterStat( | ||
784 | new Stat( | ||
785 | "OQRERequestsWaiting", | ||
786 | "Number of outgong queue refill requests waiting for processing.", | ||
787 | "", | ||
788 | "", | ||
789 | "clientstack", | ||
790 | Scene.Name, | ||
791 | StatType.Pull, | ||
792 | MeasuresOfInterest.None, | ||
793 | stat => stat.Value = OqrEngine.JobsWaiting, | ||
794 | StatVerbosity.Debug)); | ||
527 | 795 | ||
528 | // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by | 796 | // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by |
529 | // scene name | 797 | // scene name |
530 | if (UsePools) | 798 | if (UsePools) |
531 | EnablePoolStats(); | 799 | EnablePoolStats(); |
532 | 800 | ||
533 | MainConsole.Instance.Commands.AddCommand( | 801 | LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this); |
534 | "Debug", | 802 | commands.Register(); |
535 | false, | ||
536 | "debug lludp start", | ||
537 | "debug lludp start <in|out|all>", | ||
538 | "Control LLUDP packet processing.", | ||
539 | "No effect if packet processing has already started.\n" | ||
540 | + "in - start inbound processing.\n" | ||
541 | + "out - start outbound processing.\n" | ||
542 | + "all - start in and outbound processing.\n", | ||
543 | HandleStartCommand); | ||
544 | |||
545 | MainConsole.Instance.Commands.AddCommand( | ||
546 | "Debug", | ||
547 | false, | ||
548 | "debug lludp stop", | ||
549 | "debug lludp stop <in|out|all>", | ||
550 | "Stop LLUDP packet processing.", | ||
551 | "No effect if packet processing has already stopped.\n" | ||
552 | + "in - stop inbound processing.\n" | ||
553 | + "out - stop outbound processing.\n" | ||
554 | + "all - stop in and outbound processing.\n", | ||
555 | HandleStopCommand); | ||
556 | |||
557 | MainConsole.Instance.Commands.AddCommand( | ||
558 | "Debug", | ||
559 | false, | ||
560 | "debug lludp pool", | ||
561 | "debug lludp pool <on|off>", | ||
562 | "Turn object pooling within the lludp component on or off.", | ||
563 | HandlePoolCommand); | ||
564 | |||
565 | MainConsole.Instance.Commands.AddCommand( | ||
566 | "Debug", | ||
567 | false, | ||
568 | "debug lludp status", | ||
569 | "debug lludp status", | ||
570 | "Return status of LLUDP packet processing.", | ||
571 | HandleStatusCommand); | ||
572 | } | ||
573 | |||
574 | private void HandleStartCommand(string module, string[] args) | ||
575 | { | ||
576 | if (args.Length != 4) | ||
577 | { | ||
578 | MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); | ||
579 | return; | ||
580 | } | ||
581 | |||
582 | string subCommand = args[3]; | ||
583 | |||
584 | if (subCommand == "in" || subCommand == "all") | ||
585 | StartInbound(); | ||
586 | |||
587 | if (subCommand == "out" || subCommand == "all") | ||
588 | StartOutbound(); | ||
589 | } | ||
590 | |||
591 | private void HandleStopCommand(string module, string[] args) | ||
592 | { | ||
593 | if (args.Length != 4) | ||
594 | { | ||
595 | MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); | ||
596 | return; | ||
597 | } | ||
598 | |||
599 | string subCommand = args[3]; | ||
600 | |||
601 | if (subCommand == "in" || subCommand == "all") | ||
602 | StopInbound(); | ||
603 | |||
604 | if (subCommand == "out" || subCommand == "all") | ||
605 | StopOutbound(); | ||
606 | } | ||
607 | |||
608 | private void HandlePoolCommand(string module, string[] args) | ||
609 | { | ||
610 | if (args.Length != 4) | ||
611 | { | ||
612 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); | ||
613 | return; | ||
614 | } | ||
615 | |||
616 | string enabled = args[3]; | ||
617 | |||
618 | if (enabled == "on") | ||
619 | { | ||
620 | if (EnablePools()) | ||
621 | { | ||
622 | EnablePoolStats(); | ||
623 | MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_scene.Name); | ||
624 | } | ||
625 | } | ||
626 | else if (enabled == "off") | ||
627 | { | ||
628 | if (DisablePools()) | ||
629 | { | ||
630 | DisablePoolStats(); | ||
631 | MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_scene.Name); | ||
632 | } | ||
633 | } | ||
634 | else | ||
635 | { | ||
636 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); | ||
637 | } | ||
638 | } | ||
639 | |||
640 | private void HandleStatusCommand(string module, string[] args) | ||
641 | { | ||
642 | MainConsole.Instance.OutputFormat( | ||
643 | "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); | ||
644 | |||
645 | MainConsole.Instance.OutputFormat( | ||
646 | "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); | ||
647 | |||
648 | MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); | ||
649 | } | 803 | } |
650 | 804 | ||
651 | public bool HandlesRegion(Location x) | 805 | public bool HandlesRegion(Location x) |
@@ -653,45 +807,62 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
653 | return x == m_location; | 807 | return x == m_location; |
654 | } | 808 | } |
655 | 809 | ||
656 | public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) | 810 | public int GetTotalQueuedOutgoingPackets() |
657 | { | 811 | { |
658 | // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way | 812 | int total = 0; |
659 | if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) | ||
660 | allowSplitting = false; | ||
661 | 813 | ||
662 | if (allowSplitting && packet.HasVariableBlocks) | 814 | foreach (ScenePresence sp in Scene.GetScenePresences()) |
663 | { | 815 | { |
664 | byte[][] datas = packet.ToBytesMultiple(); | 816 | // XXX: Need a better way to determine which IClientAPIs have UDPClients (NPCs do not, for instance). |
665 | int packetCount = datas.Length; | 817 | if (sp.ControllingClient is LLClientView) |
666 | |||
667 | if (packetCount < 1) | ||
668 | m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); | ||
669 | |||
670 | for (int i = 0; i < packetCount; i++) | ||
671 | { | 818 | { |
672 | byte[] data = datas[i]; | 819 | LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; |
673 | m_scene.ForEachClient( | 820 | total += udpClient.GetTotalPacketsQueuedCount(); |
674 | delegate(IClientAPI client) | ||
675 | { | ||
676 | if (client is LLClientView) | ||
677 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); | ||
678 | } | ||
679 | ); | ||
680 | } | 821 | } |
681 | } | 822 | } |
682 | else | 823 | |
683 | { | 824 | return total; |
684 | byte[] data = packet.ToBytes(); | ||
685 | m_scene.ForEachClient( | ||
686 | delegate(IClientAPI client) | ||
687 | { | ||
688 | if (client is LLClientView) | ||
689 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); | ||
690 | } | ||
691 | ); | ||
692 | } | ||
693 | } | 825 | } |
694 | 826 | ||
827 | // public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) | ||
828 | // { | ||
829 | // // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way | ||
830 | // if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) | ||
831 | // allowSplitting = false; | ||
832 | // | ||
833 | // if (allowSplitting && packet.HasVariableBlocks) | ||
834 | // { | ||
835 | // byte[][] datas = packet.ToBytesMultiple(); | ||
836 | // int packetCount = datas.Length; | ||
837 | // | ||
838 | // if (packetCount < 1) | ||
839 | // m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); | ||
840 | // | ||
841 | // for (int i = 0; i < packetCount; i++) | ||
842 | // { | ||
843 | // byte[] data = datas[i]; | ||
844 | // m_scene.ForEachClient( | ||
845 | // delegate(IClientAPI client) | ||
846 | // { | ||
847 | // if (client is LLClientView) | ||
848 | // SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); | ||
849 | // } | ||
850 | // ); | ||
851 | // } | ||
852 | // } | ||
853 | // else | ||
854 | // { | ||
855 | // byte[] data = packet.ToBytes(); | ||
856 | // m_scene.ForEachClient( | ||
857 | // delegate(IClientAPI client) | ||
858 | // { | ||
859 | // if (client is LLClientView) | ||
860 | // SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); | ||
861 | // } | ||
862 | // ); | ||
863 | // } | ||
864 | // } | ||
865 | |||
695 | /// <summary> | 866 | /// <summary> |
696 | /// Start the process of sending a packet to the client. | 867 | /// Start the process of sending a packet to the client. |
697 | /// </summary> | 868 | /// </summary> |
@@ -710,6 +881,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
710 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) | 881 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) |
711 | allowSplitting = false; | 882 | allowSplitting = false; |
712 | 883 | ||
884 | bool packetQueued = false; | ||
885 | |||
713 | if (allowSplitting && packet.HasVariableBlocks) | 886 | if (allowSplitting && packet.HasVariableBlocks) |
714 | { | 887 | { |
715 | byte[][] datas = packet.ToBytesMultiple(); | 888 | byte[][] datas = packet.ToBytesMultiple(); |
@@ -721,16 +894,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
721 | for (int i = 0; i < packetCount; i++) | 894 | for (int i = 0; i < packetCount; i++) |
722 | { | 895 | { |
723 | byte[] data = datas[i]; | 896 | byte[] data = datas[i]; |
724 | SendPacketData(udpClient, data, packet.Type, category, method); | 897 | if (!SendPacketData(udpClient, data, packet.Type, category, method)) |
898 | packetQueued = true; | ||
725 | } | 899 | } |
726 | } | 900 | } |
727 | else | 901 | else |
728 | { | 902 | { |
729 | byte[] data = packet.ToBytes(); | 903 | byte[] data = packet.ToBytes(); |
730 | SendPacketData(udpClient, data, packet.Type, category, method); | 904 | if (!SendPacketData(udpClient, data, packet.Type, category, method)) |
905 | packetQueued = true; | ||
731 | } | 906 | } |
732 | 907 | ||
733 | PacketPool.Instance.ReturnPacket(packet); | 908 | PacketPool.Instance.ReturnPacket(packet); |
909 | |||
910 | if (packetQueued) | ||
911 | m_dataPresentEvent.Set(); | ||
734 | } | 912 | } |
735 | 913 | ||
736 | /// <summary> | 914 | /// <summary> |
@@ -744,7 +922,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
744 | /// The method to call if the packet is not acked by the client. If null, then a standard | 922 | /// The method to call if the packet is not acked by the client. If null, then a standard |
745 | /// resend of the packet is done. | 923 | /// resend of the packet is done. |
746 | /// </param> | 924 | /// </param> |
747 | public void SendPacketData( | 925 | /// <returns>true if the data was sent immediately, false if it was queued for sending</returns> |
926 | public bool SendPacketData( | ||
748 | LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) | 927 | LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) |
749 | { | 928 | { |
750 | int dataLength = data.Length; | 929 | int dataLength = data.Length; |
@@ -801,15 +980,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
801 | #region Queue or Send | 980 | #region Queue or Send |
802 | 981 | ||
803 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); | 982 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); |
983 | |||
804 | // If we were not provided a method for handling unacked, use the UDPServer default method | 984 | // If we were not provided a method for handling unacked, use the UDPServer default method |
805 | outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); | 985 | if ((outgoingPacket.Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0) |
986 | outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); | ||
806 | 987 | ||
807 | // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will | 988 | // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will |
808 | // continue to display the deleted object until relog. Therefore, we need to always queue a kill object | 989 | // continue to display the deleted object until relog. Therefore, we need to always queue a kill object |
809 | // packet so that it isn't sent before a queued update packet. | 990 | // packet so that it isn't sent before a queued update packet. |
810 | bool requestQueue = type == PacketType.KillObject; | 991 | bool forceQueue = (type == PacketType.KillObject); |
811 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) | 992 | |
993 | // if (type == PacketType.ImprovedTerseObjectUpdate) | ||
994 | // { | ||
995 | // m_log.DebugFormat("Direct send ITOU to {0} in {1}", udpClient.AgentID, Scene.Name); | ||
996 | // SendPacketFinal(outgoingPacket); | ||
997 | // return false; | ||
998 | // } | ||
999 | // else | ||
1000 | // { | ||
1001 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, forceQueue)) | ||
1002 | { | ||
812 | SendPacketFinal(outgoingPacket); | 1003 | SendPacketFinal(outgoingPacket); |
1004 | return true; | ||
1005 | } | ||
1006 | else | ||
1007 | { | ||
1008 | return false; | ||
1009 | } | ||
1010 | // } | ||
813 | 1011 | ||
814 | #endregion Queue or Send | 1012 | #endregion Queue or Send |
815 | } | 1013 | } |
@@ -885,7 +1083,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
885 | // Fire this out on a different thread so that we don't hold up outgoing packet processing for | 1083 | // Fire this out on a different thread so that we don't hold up outgoing packet processing for |
886 | // everybody else if this is being called due to an ack timeout. | 1084 | // everybody else if this is being called due to an ack timeout. |
887 | // This is the same as processing as the async process of a logout request. | 1085 | // This is the same as processing as the async process of a logout request. |
888 | Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); | 1086 | Util.FireAndForget( |
1087 | o => DeactivateClientDueToTimeout(client, timeoutTicks), null, "LLUDPServer.DeactivateClientDueToTimeout"); | ||
889 | 1088 | ||
890 | return; | 1089 | return; |
891 | } | 1090 | } |
@@ -981,7 +1180,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
981 | Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); | 1180 | Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); |
982 | outgoingPacket.SequenceNumber = sequenceNumber; | 1181 | outgoingPacket.SequenceNumber = sequenceNumber; |
983 | 1182 | ||
984 | if (isReliable) | 1183 | if (udpClient.ProcessUnackedSends && isReliable) |
985 | { | 1184 | { |
986 | // Add this packet to the list of ACK responses we are waiting on from the server | 1185 | // Add this packet to the list of ACK responses we are waiting on from the server |
987 | udpClient.NeedAcks.Add(outgoingPacket); | 1186 | udpClient.NeedAcks.Add(outgoingPacket); |
@@ -990,6 +1189,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
990 | else | 1189 | else |
991 | { | 1190 | { |
992 | Interlocked.Increment(ref udpClient.PacketsResent); | 1191 | Interlocked.Increment(ref udpClient.PacketsResent); |
1192 | |||
1193 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
1194 | // is 100% correct | ||
1195 | PacketsResentCount++; | ||
993 | } | 1196 | } |
994 | 1197 | ||
995 | #endregion Sequence Number Assignment | 1198 | #endregion Sequence Number Assignment |
@@ -997,6 +1200,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
997 | // Stats tracking | 1200 | // Stats tracking |
998 | Interlocked.Increment(ref udpClient.PacketsSent); | 1201 | Interlocked.Increment(ref udpClient.PacketsSent); |
999 | 1202 | ||
1203 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
1204 | // is 100% correct | ||
1205 | PacketsSentCount++; | ||
1206 | |||
1207 | if (udpClient.DebugDataOutLevel > 0) | ||
1208 | m_log.DebugFormat( | ||
1209 | "[LLUDPSERVER]: Sending packet #{0} (rel: {1}, res: {2}) to {3} from {4}", | ||
1210 | outgoingPacket.SequenceNumber, isReliable, isResend, udpClient.AgentID, Scene.Name); | ||
1211 | |||
1000 | // Put the UDP payload on the wire | 1212 | // Put the UDP payload on the wire |
1001 | AsyncBeginSend(buffer); | 1213 | AsyncBeginSend(buffer); |
1002 | 1214 | ||
@@ -1004,6 +1216,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1004 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; | 1216 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; |
1005 | } | 1217 | } |
1006 | 1218 | ||
1219 | private void RecordMalformedInboundPacket(IPEndPoint endPoint) | ||
1220 | { | ||
1221 | // if (m_malformedCount < 100) | ||
1222 | // m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); | ||
1223 | |||
1224 | IncomingMalformedPacketCount++; | ||
1225 | |||
1226 | if ((IncomingMalformedPacketCount % 10000) == 0) | ||
1227 | m_log.WarnFormat( | ||
1228 | "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}", | ||
1229 | IncomingMalformedPacketCount, endPoint); | ||
1230 | } | ||
1231 | |||
1007 | public override void PacketReceived(UDPPacketBuffer buffer) | 1232 | public override void PacketReceived(UDPPacketBuffer buffer) |
1008 | { | 1233 | { |
1009 | // Debugging/Profiling | 1234 | // Debugging/Profiling |
@@ -1025,6 +1250,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1025 | // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", | 1250 | // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", |
1026 | // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | 1251 | // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); |
1027 | 1252 | ||
1253 | RecordMalformedInboundPacket(endPoint); | ||
1254 | |||
1028 | return; // Drop undersized packet | 1255 | return; // Drop undersized packet |
1029 | } | 1256 | } |
1030 | 1257 | ||
@@ -1043,6 +1270,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1043 | // "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", | 1270 | // "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", |
1044 | // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | 1271 | // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); |
1045 | 1272 | ||
1273 | RecordMalformedInboundPacket(endPoint); | ||
1274 | |||
1046 | return; // Malformed header | 1275 | return; // Malformed header |
1047 | } | 1276 | } |
1048 | 1277 | ||
@@ -1058,34 +1287,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1058 | // Only allocate a buffer for zerodecoding if the packet is zerocoded | 1287 | // Only allocate a buffer for zerodecoding if the packet is zerocoded |
1059 | ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); | 1288 | ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); |
1060 | } | 1289 | } |
1061 | catch (MalformedDataException) | ||
1062 | { | ||
1063 | } | ||
1064 | catch (IndexOutOfRangeException) | ||
1065 | { | ||
1066 | // m_log.WarnFormat( | ||
1067 | // "[LLUDPSERVER]: Dropping short packet received from {0} in {1}", | ||
1068 | // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | ||
1069 | |||
1070 | return; // Drop short packet | ||
1071 | } | ||
1072 | catch (Exception e) | 1290 | catch (Exception e) |
1073 | { | 1291 | { |
1074 | if (m_malformedCount < 100) | 1292 | if (IncomingMalformedPacketCount < 100) |
1075 | m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); | 1293 | m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); |
1076 | |||
1077 | m_malformedCount++; | ||
1078 | |||
1079 | if ((m_malformedCount % 100000) == 0) | ||
1080 | m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount); | ||
1081 | } | 1294 | } |
1082 | 1295 | ||
1083 | // Fail-safe check | 1296 | // Fail-safe check |
1084 | if (packet == null) | 1297 | if (packet == null) |
1085 | { | 1298 | { |
1086 | m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", | 1299 | if (IncomingMalformedPacketCount < 100) |
1087 | buffer.DataLength, buffer.RemoteEndPoint); | 1300 | { |
1088 | m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | 1301 | m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:", |
1302 | buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | ||
1303 | } | ||
1304 | |||
1305 | RecordMalformedInboundPacket(endPoint); | ||
1306 | |||
1089 | return; | 1307 | return; |
1090 | } | 1308 | } |
1091 | 1309 | ||
@@ -1100,16 +1318,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1100 | // buffer. | 1318 | // buffer. |
1101 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | 1319 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; |
1102 | 1320 | ||
1103 | Util.FireAndForget(HandleUseCircuitCode, array); | 1321 | Util.FireAndForget(HandleUseCircuitCode, array, "LLUDPServer.HandleUseCircuitCode"); |
1322 | |||
1323 | return; | ||
1324 | } | ||
1325 | else if (packet.Type == PacketType.CompleteAgentMovement) | ||
1326 | { | ||
1327 | // Send ack straight away to let the viewer know that we got it. | ||
1328 | SendAckImmediate(endPoint, packet.Header.Sequence); | ||
1329 | |||
1330 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the | ||
1331 | // buffer. | ||
1332 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | ||
1333 | |||
1334 | Util.FireAndForget( | ||
1335 | HandleCompleteMovementIntoRegion, array, "LLUDPServer.HandleCompleteMovementIntoRegion"); | ||
1104 | 1336 | ||
1105 | return; | 1337 | return; |
1106 | } | 1338 | } |
1107 | 1339 | ||
1108 | // Determine which agent this packet came from | 1340 | // Determine which agent this packet came from |
1109 | IClientAPI client; | 1341 | IClientAPI client; |
1110 | if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) | 1342 | if (!Scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) |
1111 | { | 1343 | { |
1112 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 1344 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
1345 | |||
1346 | IncomingOrphanedPacketCount++; | ||
1347 | |||
1348 | if ((IncomingOrphanedPacketCount % 10000) == 0) | ||
1349 | m_log.WarnFormat( | ||
1350 | "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}", | ||
1351 | IncomingOrphanedPacketCount, endPoint); | ||
1352 | |||
1113 | return; | 1353 | return; |
1114 | } | 1354 | } |
1115 | 1355 | ||
@@ -1128,30 +1368,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1128 | 1368 | ||
1129 | #region ACK Receiving | 1369 | #region ACK Receiving |
1130 | 1370 | ||
1131 | // Handle appended ACKs | 1371 | if (udpClient.ProcessUnackedSends) |
1132 | if (packet.Header.AppendedAcks && packet.Header.AckList != null) | ||
1133 | { | 1372 | { |
1134 | // m_log.DebugFormat( | 1373 | // Handle appended ACKs |
1135 | // "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}", | 1374 | if (packet.Header.AppendedAcks && packet.Header.AckList != null) |
1136 | // packet.Header.AckList.Length, client.Name, m_scene.Name); | 1375 | { |
1376 | // m_log.DebugFormat( | ||
1377 | // "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}", | ||
1378 | // packet.Header.AckList.Length, client.Name, m_scene.Name); | ||
1137 | 1379 | ||
1138 | for (int i = 0; i < packet.Header.AckList.Length; i++) | 1380 | for (int i = 0; i < packet.Header.AckList.Length; i++) |
1139 | udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent); | 1381 | udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent); |
1140 | } | 1382 | } |
1141 | 1383 | ||
1142 | // Handle PacketAck packets | 1384 | // Handle PacketAck packets |
1143 | if (packet.Type == PacketType.PacketAck) | 1385 | if (packet.Type == PacketType.PacketAck) |
1144 | { | 1386 | { |
1145 | PacketAckPacket ackPacket = (PacketAckPacket)packet; | 1387 | PacketAckPacket ackPacket = (PacketAckPacket)packet; |
1146 | 1388 | ||
1147 | // m_log.DebugFormat( | 1389 | // m_log.DebugFormat( |
1148 | // "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}", | 1390 | // "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}", |
1149 | // ackPacket.Packets.Length, client.Name, m_scene.Name); | 1391 | // ackPacket.Packets.Length, client.Name, m_scene.Name); |
1150 | 1392 | ||
1151 | for (int i = 0; i < ackPacket.Packets.Length; i++) | 1393 | for (int i = 0; i < ackPacket.Packets.Length; i++) |
1152 | udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent); | 1394 | udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent); |
1153 | 1395 | ||
1154 | // We don't need to do anything else with PacketAck packets | 1396 | // We don't need to do anything else with PacketAck packets |
1397 | return; | ||
1398 | } | ||
1399 | } | ||
1400 | else if (packet.Type == PacketType.PacketAck) | ||
1401 | { | ||
1155 | return; | 1402 | return; |
1156 | } | 1403 | } |
1157 | 1404 | ||
@@ -1185,6 +1432,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1185 | 1432 | ||
1186 | #region Incoming Packet Accounting | 1433 | #region Incoming Packet Accounting |
1187 | 1434 | ||
1435 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
1436 | // is 100% correct | ||
1437 | if (packet.Header.Resent) | ||
1438 | IncomingPacketsResentCount++; | ||
1439 | |||
1188 | // Check the archive of received reliable packet IDs to see whether we already received this packet | 1440 | // Check the archive of received reliable packet IDs to see whether we already received this packet |
1189 | if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) | 1441 | if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) |
1190 | { | 1442 | { |
@@ -1207,6 +1459,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1207 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); | 1459 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); |
1208 | #endregion BinaryStats | 1460 | #endregion BinaryStats |
1209 | 1461 | ||
1462 | if (packet.Type == PacketType.AgentUpdate) | ||
1463 | { | ||
1464 | if (DiscardInboundAgentUpdates) | ||
1465 | return; | ||
1466 | |||
1467 | ((LLClientView)client).TotalAgentUpdates++; | ||
1468 | |||
1469 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; | ||
1470 | |||
1471 | LLClientView llClient = client as LLClientView; | ||
1472 | if (agentUpdate.AgentData.SessionID != client.SessionId | ||
1473 | || agentUpdate.AgentData.AgentID != client.AgentId | ||
1474 | || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) ) | ||
1475 | { | ||
1476 | PacketPool.Instance.ReturnPacket(packet); | ||
1477 | return; | ||
1478 | } | ||
1479 | } | ||
1480 | |||
1210 | #region Ping Check Handling | 1481 | #region Ping Check Handling |
1211 | 1482 | ||
1212 | if (packet.Type == PacketType.StartPingCheck) | 1483 | if (packet.Type == PacketType.StartPingCheck) |
@@ -1266,8 +1537,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1266 | static object binStatsLogLock = new object(); | 1537 | static object binStatsLogLock = new object(); |
1267 | static string binStatsDir = ""; | 1538 | static string binStatsDir = ""; |
1268 | 1539 | ||
1540 | //for Aggregated In/Out BW logging | ||
1541 | static bool m_aggregatedBWStats = false; | ||
1542 | static long m_aggregatedBytesIn = 0; | ||
1543 | static long m_aggregatedByestOut = 0; | ||
1544 | static object aggBWStatsLock = new object(); | ||
1545 | |||
1546 | public static long AggregatedLLUDPBytesIn | ||
1547 | { | ||
1548 | get { return m_aggregatedBytesIn; } | ||
1549 | } | ||
1550 | public static long AggregatedLLUDPBytesOut | ||
1551 | { | ||
1552 | get {return m_aggregatedByestOut;} | ||
1553 | } | ||
1554 | |||
1269 | public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size) | 1555 | public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size) |
1270 | { | 1556 | { |
1557 | if (m_aggregatedBWStats) | ||
1558 | { | ||
1559 | lock (aggBWStatsLock) | ||
1560 | { | ||
1561 | if (incoming) | ||
1562 | m_aggregatedBytesIn += size; | ||
1563 | else | ||
1564 | m_aggregatedByestOut += size; | ||
1565 | } | ||
1566 | } | ||
1567 | |||
1271 | if (!m_shouldCollectStats) return; | 1568 | if (!m_shouldCollectStats) return; |
1272 | 1569 | ||
1273 | // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size | 1570 | // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size |
@@ -1344,7 +1641,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1344 | 1641 | ||
1345 | m_log.DebugFormat( | 1642 | m_log.DebugFormat( |
1346 | "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", | 1643 | "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", |
1347 | uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint); | 1644 | uccp.CircuitCode.Code, Scene.RegionInfo.RegionName, endPoint); |
1348 | 1645 | ||
1349 | AuthenticateResponse sessionInfo; | 1646 | AuthenticateResponse sessionInfo; |
1350 | if (IsClientAuthorized(uccp, out sessionInfo)) | 1647 | if (IsClientAuthorized(uccp, out sessionInfo)) |
@@ -1365,14 +1662,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1365 | 1662 | ||
1366 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | 1663 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1367 | if (client != null) | 1664 | if (client != null) |
1368 | client.SceneAgent.SendInitialDataToMe(); | 1665 | { |
1666 | AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code); | ||
1667 | bool tp = (aCircuit.teleportFlags > 0); | ||
1668 | // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from | ||
1669 | if (!tp && !client.SceneAgent.SentInitialDataToClient) | ||
1670 | client.SceneAgent.SendInitialDataToClient(); | ||
1671 | } | ||
1369 | } | 1672 | } |
1370 | else | 1673 | else |
1371 | { | 1674 | { |
1372 | // Don't create clients for unauthorized requesters. | 1675 | // Don't create clients for unauthorized requesters. |
1373 | m_log.WarnFormat( | 1676 | m_log.WarnFormat( |
1374 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", | 1677 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", |
1375 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); | 1678 | uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); |
1376 | } | 1679 | } |
1377 | 1680 | ||
1378 | // m_log.DebugFormat( | 1681 | // m_log.DebugFormat( |
@@ -1392,6 +1695,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1392 | } | 1695 | } |
1393 | } | 1696 | } |
1394 | 1697 | ||
1698 | private void HandleCompleteMovementIntoRegion(object o) | ||
1699 | { | ||
1700 | IPEndPoint endPoint = null; | ||
1701 | IClientAPI client = null; | ||
1702 | |||
1703 | try | ||
1704 | { | ||
1705 | object[] array = (object[])o; | ||
1706 | endPoint = (IPEndPoint)array[0]; | ||
1707 | CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; | ||
1708 | |||
1709 | m_log.DebugFormat( | ||
1710 | "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, Scene.Name); | ||
1711 | |||
1712 | // Determine which agent this packet came from | ||
1713 | // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination | ||
1714 | // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode | ||
1715 | // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these | ||
1716 | // packets asynchronously, we need to account for this thread proceeding more quickly than the | ||
1717 | // UseCircuitCode thread. | ||
1718 | int count = 40; | ||
1719 | while (count-- > 0) | ||
1720 | { | ||
1721 | if (Scene.TryGetClient(endPoint, out client)) | ||
1722 | { | ||
1723 | if (!client.IsActive) | ||
1724 | { | ||
1725 | // This check exists to catch a condition where the client has been closed by another thread | ||
1726 | // but has not yet been removed from the client manager (and possibly a new connection has | ||
1727 | // not yet been established). | ||
1728 | m_log.DebugFormat( | ||
1729 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.", | ||
1730 | endPoint, client.Name, Scene.Name); | ||
1731 | } | ||
1732 | else if (client.SceneAgent == null) | ||
1733 | { | ||
1734 | // This check exists to catch a condition where the new client has been added to the client | ||
1735 | // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too | ||
1736 | // eager, then the new ScenePresence may not have registered a listener for this messsage | ||
1737 | // before we try to process it. | ||
1738 | // XXX: A better long term fix may be to add the SceneAgent before the client is added to | ||
1739 | // the client manager | ||
1740 | m_log.DebugFormat( | ||
1741 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.", | ||
1742 | endPoint, client.Name, Scene.Name); | ||
1743 | } | ||
1744 | else | ||
1745 | { | ||
1746 | break; | ||
1747 | } | ||
1748 | } | ||
1749 | else | ||
1750 | { | ||
1751 | m_log.DebugFormat( | ||
1752 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.", | ||
1753 | endPoint, Scene.Name); | ||
1754 | } | ||
1755 | |||
1756 | Thread.Sleep(200); | ||
1757 | } | ||
1758 | |||
1759 | if (client == null) | ||
1760 | { | ||
1761 | m_log.DebugFormat( | ||
1762 | "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.", | ||
1763 | endPoint, Scene.Name); | ||
1764 | |||
1765 | return; | ||
1766 | } | ||
1767 | else if (!client.IsActive || client.SceneAgent == null) | ||
1768 | { | ||
1769 | // This check exists to catch a condition where the client has been closed by another thread | ||
1770 | // but has not yet been removed from the client manager. | ||
1771 | // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging | ||
1772 | // purposes. | ||
1773 | m_log.DebugFormat( | ||
1774 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.", | ||
1775 | endPoint, client.Name, Scene.Name); | ||
1776 | |||
1777 | return; | ||
1778 | } | ||
1779 | |||
1780 | IncomingPacket incomingPacket1; | ||
1781 | |||
1782 | // Inbox insertion | ||
1783 | if (UsePools) | ||
1784 | { | ||
1785 | incomingPacket1 = m_incomingPacketPool.GetObject(); | ||
1786 | incomingPacket1.Client = (LLClientView)client; | ||
1787 | incomingPacket1.Packet = packet; | ||
1788 | } | ||
1789 | else | ||
1790 | { | ||
1791 | incomingPacket1 = new IncomingPacket((LLClientView)client, packet); | ||
1792 | } | ||
1793 | |||
1794 | packetInbox.Enqueue(incomingPacket1); | ||
1795 | } | ||
1796 | catch (Exception e) | ||
1797 | { | ||
1798 | m_log.ErrorFormat( | ||
1799 | "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", | ||
1800 | endPoint != null ? endPoint.ToString() : "n/a", | ||
1801 | client != null ? client.Name : "unknown", | ||
1802 | client != null ? client.AgentId.ToString() : "unknown", | ||
1803 | e.Message, | ||
1804 | e.StackTrace); | ||
1805 | } | ||
1806 | } | ||
1807 | |||
1395 | /// <summary> | 1808 | /// <summary> |
1396 | /// Send an ack immediately to the given endpoint. | 1809 | /// Send an ack immediately to the given endpoint. |
1397 | /// </summary> | 1810 | /// </summary> |
@@ -1454,12 +1867,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1454 | // consistently, this lock could probably be removed. | 1867 | // consistently, this lock could probably be removed. |
1455 | lock (this) | 1868 | lock (this) |
1456 | { | 1869 | { |
1457 | if (!m_scene.TryGetClient(agentID, out client)) | 1870 | if (!Scene.TryGetClient(agentID, out client)) |
1458 | { | 1871 | { |
1459 | LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); | 1872 | LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); |
1460 | 1873 | ||
1461 | client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); | 1874 | client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); |
1462 | client.OnLogout += LogoutHandler; | 1875 | client.OnLogout += LogoutHandler; |
1876 | client.DebugPacketLevel = DefaultClientPacketDebugLevel; | ||
1463 | 1877 | ||
1464 | ((LLClientView)client).DisableFacelights = m_disableFacelights; | 1878 | ((LLClientView)client).DisableFacelights = m_disableFacelights; |
1465 | 1879 | ||
@@ -1478,25 +1892,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1478 | /// regular client pings. | 1892 | /// regular client pings. |
1479 | /// </remarks> | 1893 | /// </remarks> |
1480 | /// <param name='client'></param> | 1894 | /// <param name='client'></param> |
1481 | private void DeactivateClientDueToTimeout(LLClientView client) | 1895 | /// <param name='timeoutTicks'></param> |
1896 | private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks) | ||
1482 | { | 1897 | { |
1483 | lock (client.CloseSyncLock) | 1898 | lock (client.CloseSyncLock) |
1484 | { | 1899 | { |
1900 | ClientLogoutsDueToNoReceives++; | ||
1901 | |||
1485 | m_log.WarnFormat( | 1902 | m_log.WarnFormat( |
1486 | "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", | 1903 | "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.", |
1487 | client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); | 1904 | client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, Scene.Name); |
1488 | |||
1489 | StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); | ||
1490 | 1905 | ||
1491 | if (!client.SceneAgent.IsChildAgent) | 1906 | if (!client.SceneAgent.IsChildAgent) |
1492 | client.Kick("Simulator logged you out due to connection timeout"); | 1907 | client.Kick("Simulator logged you out due to connection timeout."); |
1493 | |||
1494 | client.CloseWithoutChecks(); | ||
1495 | } | 1908 | } |
1909 | |||
1910 | Scene.CloseAgent(client.AgentId, true); | ||
1496 | } | 1911 | } |
1497 | 1912 | ||
1498 | private void IncomingPacketHandler() | 1913 | private void IncomingPacketHandler() |
1499 | { | 1914 | { |
1915 | Thread.CurrentThread.Priority = ThreadPriority.Highest; | ||
1916 | |||
1500 | // Set this culture for the thread that incoming packets are received | 1917 | // Set this culture for the thread that incoming packets are received |
1501 | // on to en-US to avoid number parsing issues | 1918 | // on to en-US to avoid number parsing issues |
1502 | Culture.SetCurrentCulture(); | 1919 | Culture.SetCurrentCulture(); |
@@ -1507,6 +1924,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1507 | { | 1924 | { |
1508 | IncomingPacket incomingPacket = null; | 1925 | IncomingPacket incomingPacket = null; |
1509 | 1926 | ||
1927 | /* | ||
1510 | // HACK: This is a test to try and rate limit packet handling on Mono. | 1928 | // HACK: This is a test to try and rate limit packet handling on Mono. |
1511 | // If it works, a more elegant solution can be devised | 1929 | // If it works, a more elegant solution can be devised |
1512 | if (Util.FireAndForgetCount() < 2) | 1930 | if (Util.FireAndForgetCount() < 2) |
@@ -1514,6 +1932,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1514 | //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); | 1932 | //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); |
1515 | Thread.Sleep(30); | 1933 | Thread.Sleep(30); |
1516 | } | 1934 | } |
1935 | */ | ||
1517 | 1936 | ||
1518 | if (packetInbox.Dequeue(100, ref incomingPacket)) | 1937 | if (packetInbox.Dequeue(100, ref incomingPacket)) |
1519 | { | 1938 | { |
@@ -1540,6 +1959,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1540 | 1959 | ||
1541 | private void OutgoingPacketHandler() | 1960 | private void OutgoingPacketHandler() |
1542 | { | 1961 | { |
1962 | Thread.CurrentThread.Priority = ThreadPriority.Highest; | ||
1963 | |||
1543 | // Set this culture for the thread that outgoing packets are sent | 1964 | // Set this culture for the thread that outgoing packets are sent |
1544 | // on to en-US to avoid number parsing issues | 1965 | // on to en-US to avoid number parsing issues |
1545 | Culture.SetCurrentCulture(); | 1966 | Culture.SetCurrentCulture(); |
@@ -1602,14 +2023,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1602 | 2023 | ||
1603 | // Handle outgoing packets, resends, acknowledgements, and pings for each | 2024 | // Handle outgoing packets, resends, acknowledgements, and pings for each |
1604 | // client. m_packetSent will be set to true if a packet is sent | 2025 | // client. m_packetSent will be set to true if a packet is sent |
1605 | m_scene.ForEachClient(clientPacketHandler); | 2026 | Scene.ForEachClient(clientPacketHandler); |
1606 | 2027 | ||
1607 | m_currentOutgoingClient = null; | 2028 | m_currentOutgoingClient = null; |
1608 | 2029 | ||
1609 | // If nothing was sent, sleep for the minimum amount of time before a | 2030 | // If nothing was sent, sleep for the minimum amount of time before a |
1610 | // token bucket could get more tokens | 2031 | // token bucket could get more tokens |
2032 | //if (!m_packetSent) | ||
2033 | // Thread.Sleep((int)TickCountResolution); | ||
2034 | // | ||
2035 | // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with | ||
2036 | // modern mono it reduces CPU base load since there is no more continuous polling. | ||
1611 | if (!m_packetSent) | 2037 | if (!m_packetSent) |
1612 | Thread.Sleep((int)TickCountResolution); | 2038 | m_dataPresentEvent.WaitOne(100); |
1613 | 2039 | ||
1614 | Watchdog.UpdateThread(); | 2040 | Watchdog.UpdateThread(); |
1615 | } | 2041 | } |
@@ -1635,7 +2061,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1635 | 2061 | ||
1636 | if (udpClient.IsConnected) | 2062 | if (udpClient.IsConnected) |
1637 | { | 2063 | { |
1638 | if (m_resendUnacked) | 2064 | if (udpClient.ProcessUnackedSends && m_resendUnacked) |
1639 | HandleUnacked(llClient); | 2065 | HandleUnacked(llClient); |
1640 | 2066 | ||
1641 | if (m_sendAcks) | 2067 | if (m_sendAcks) |
@@ -1764,7 +2190,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1764 | watch1.Reset(); | 2190 | watch1.Reset(); |
1765 | 2191 | ||
1766 | // reuse this -- it's every ~100ms | 2192 | // reuse this -- it's every ~100ms |
1767 | if (m_scene.EmergencyMonitoring && nticks % 100 == 0) | 2193 | if (Scene.EmergencyMonitoring && nticks % 100 == 0) |
1768 | { | 2194 | { |
1769 | m_log.InfoFormat("[LLUDPSERVER]: avg processing ticks: {0} avg unacked: {1} avg acks: {2} avg ping: {3} avg dequeue: {4} (TickCountRes: {5} sent: {6} notsent: {7})", | 2195 | m_log.InfoFormat("[LLUDPSERVER]: avg processing ticks: {0} avg unacked: {1} avg acks: {2} avg ping: {3} avg dequeue: {4} (TickCountRes: {5} sent: {6} notsent: {7})", |
1770 | avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent); | 2196 | avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent); |
@@ -1813,7 +2239,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1813 | { | 2239 | { |
1814 | m_log.DebugFormat( | 2240 | m_log.DebugFormat( |
1815 | "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", | 2241 | "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", |
1816 | packet.Type, client.Name, m_scene.RegionInfo.RegionName); | 2242 | packet.Type, client.Name, Scene.RegionInfo.RegionName); |
1817 | } | 2243 | } |
1818 | 2244 | ||
1819 | IncomingPacketsProcessed++; | 2245 | IncomingPacketsProcessed++; |
@@ -1826,8 +2252,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1826 | if (!client.IsLoggingOut) | 2252 | if (!client.IsLoggingOut) |
1827 | { | 2253 | { |
1828 | client.IsLoggingOut = true; | 2254 | client.IsLoggingOut = true; |
1829 | client.Close(); | 2255 | Scene.CloseAgent(client.AgentId, false); |
1830 | } | 2256 | } |
1831 | } | 2257 | } |
1832 | } | 2258 | } |
1833 | } \ No newline at end of file | 2259 | } |