aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs160
1 files changed, 115 insertions, 45 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 75f783b..3c23dcf 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -147,21 +147,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
147 private int m_elapsed500MSOutgoingPacketHandler; 147 private int m_elapsed500MSOutgoingPacketHandler;
148 148
149 /// <summary>Flag to signal when clients should check for resends</summary> 149 /// <summary>Flag to signal when clients should check for resends</summary>
150 private bool m_resendUnacked; 150 protected bool m_resendUnacked;
151
151 /// <summary>Flag to signal when clients should send ACKs</summary> 152 /// <summary>Flag to signal when clients should send ACKs</summary>
152 private bool m_sendAcks; 153 protected bool m_sendAcks;
154
153 /// <summary>Flag to signal when clients should send pings</summary> 155 /// <summary>Flag to signal when clients should send pings</summary>
154 private bool m_sendPing; 156 protected bool m_sendPing;
155 157
156 private int m_defaultRTO = 0; 158 private int m_defaultRTO = 0;
157 private int m_maxRTO = 0; 159 private int m_maxRTO = 0;
158 160 private int m_ackTimeout = 0;
161 private int m_pausedAckTimeout = 0;
159 private bool m_disableFacelights = false; 162 private bool m_disableFacelights = false;
160 163
161 public Socket Server { get { return null; } } 164 public Socket Server { get { return null; } }
162 165
163 private int m_malformedCount = 0; // Guard against a spamming attack 166 private int m_malformedCount = 0; // Guard against a spamming attack
164 167
168 /// <summary>
169 /// Record current outgoing client for monitoring purposes.
170 /// </summary>
171 private IClientAPI m_currentOutgoingClient;
172
173 /// <summary>
174 /// Recording current incoming client for monitoring purposes.
175 /// </summary>
176 private IClientAPI m_currentIncomingClient;
177
165 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 178 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
166 : base(listenIP, (int)port) 179 : base(listenIP, (int)port)
167 { 180 {
@@ -198,11 +211,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
198 m_defaultRTO = config.GetInt("DefaultRTO", 0); 211 m_defaultRTO = config.GetInt("DefaultRTO", 0);
199 m_maxRTO = config.GetInt("MaxRTO", 0); 212 m_maxRTO = config.GetInt("MaxRTO", 0);
200 m_disableFacelights = config.GetBoolean("DisableFacelights", false); 213 m_disableFacelights = config.GetBoolean("DisableFacelights", false);
214 m_ackTimeout = 1000 * config.GetInt("AckTimeout", 60);
215 m_pausedAckTimeout = 1000 * config.GetInt("PausedAckTimeout", 300);
201 } 216 }
202 else 217 else
203 { 218 {
204 PrimUpdatesPerCallback = 100; 219 PrimUpdatesPerCallback = 100;
205 TextureSendLimit = 20; 220 TextureSendLimit = 20;
221 m_ackTimeout = 1000 * 60; // 1 minute
222 m_pausedAckTimeout = 1000 * 300; // 5 minutes
206 } 223 }
207 224
208 #region BinaryStats 225 #region BinaryStats
@@ -239,19 +256,56 @@ namespace OpenSim.Region.ClientStack.LindenUDP
239 if (m_scene == null) 256 if (m_scene == null)
240 throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); 257 throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference");
241 258
242 m_log.Info("[LLUDPSERVER]: Starting the LLUDP server in " + (m_asyncPacketHandling ? "asynchronous" : "synchronous") + " mode"); 259 m_log.InfoFormat(
260 "[LLUDPSERVER]: Starting the LLUDP server in {0} mode",
261 m_asyncPacketHandling ? "asynchronous" : "synchronous");
243 262
244 base.Start(m_recvBufferSize, m_asyncPacketHandling); 263 base.Start(m_recvBufferSize, m_asyncPacketHandling);
245 264
246 // Start the packet processing threads 265 // Start the packet processing threads
247 Watchdog.StartThread( 266 Watchdog.StartThread(
248 IncomingPacketHandler, "Incoming Packets (" + m_scene.RegionInfo.RegionName + ")", ThreadPriority.Normal, false, true); 267 IncomingPacketHandler,
268 string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName),
269 ThreadPriority.Normal,
270 false,
271 true,
272 GetWatchdogIncomingAlarmData,
273 Watchdog.WATCHDOG_TIMEOUT_MS);
274
249 Watchdog.StartThread( 275 Watchdog.StartThread(
250 OutgoingPacketHandler, "Outgoing Packets (" + m_scene.RegionInfo.RegionName + ")", ThreadPriority.Normal, false, true); 276 OutgoingPacketHandler,
277 string.Format("Outgoing Packets ({0})", m_scene.RegionInfo.RegionName),
278 ThreadPriority.Normal,
279 false,
280 true,
281 GetWatchdogOutgoingAlarmData,
282 Watchdog.WATCHDOG_TIMEOUT_MS);
251 283
252 m_elapsedMSSinceLastStatReport = Environment.TickCount; 284 m_elapsedMSSinceLastStatReport = Environment.TickCount;
253 } 285 }
254 286
287 /// <summary>
288 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
289 /// </summary>
290 /// <returns></returns>
291 private string GetWatchdogIncomingAlarmData()
292 {
293 return string.Format(
294 "Client is {0}",
295 m_currentIncomingClient != null ? m_currentIncomingClient.Name : "none");
296 }
297
298 /// <summary>
299 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
300 /// </summary>
301 /// <returns></returns>
302 private string GetWatchdogOutgoingAlarmData()
303 {
304 return string.Format(
305 "Client is {0}",
306 m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none");
307 }
308
255 public new void Stop() 309 public new void Stop()
256 { 310 {
257 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); 311 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
@@ -485,19 +539,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
485 SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null); 539 SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null);
486 } 540 }
487 541
488 public void HandleUnacked(LLUDPClient udpClient) 542 public void HandleUnacked(LLClientView client)
489 { 543 {
544 LLUDPClient udpClient = client.UDPClient;
545
490 if (!udpClient.IsConnected) 546 if (!udpClient.IsConnected)
491 return; 547 return;
492 548
493 // Disconnect an agent if no packets are received for some time 549 // Disconnect an agent if no packets are received for some time
494 //FIXME: Make 60 an .ini setting 550 int timeoutTicks = m_ackTimeout;
495 if ((Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > 1000 * 60) 551
552 // Allow more slack if the client is "paused" eg file upload dialogue is open
553 // Some sort of limit is needed in case the client crashes, loses its network connection
554 // or some other disaster prevents it from sendung the AgentResume
555 if (udpClient.IsPaused)
556 timeoutTicks = m_pausedAckTimeout;
557
558 if (!client.IsLoggingOut &&
559 (Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > timeoutTicks)
496 { 560 {
497 m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); 561 m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID);
498 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); 562 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
563 RemoveClient(client);
499 564
500 RemoveClient(udpClient);
501 return; 565 return;
502 } 566 }
503 567
@@ -820,7 +884,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
820 #endregion Ping Check Handling 884 #endregion Ping Check Handling
821 885
822 // Inbox insertion 886 // Inbox insertion
823 packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); 887 packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet));
824 } 888 }
825 889
826 #region BinaryStats 890 #region BinaryStats
@@ -916,7 +980,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
916 UDPPacketBuffer buffer = (UDPPacketBuffer)array[0]; 980 UDPPacketBuffer buffer = (UDPPacketBuffer)array[0];
917 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; 981 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
918 982
919 m_log.DebugFormat("[LLUDPSERVER]: Handling UseCircuitCode request from {0}", buffer.RemoteEndPoint); 983 m_log.DebugFormat(
984 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} from {1}",
985 uccp.CircuitCode.Code, buffer.RemoteEndPoint);
920 986
921 remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint; 987 remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
922 988
@@ -1044,15 +1110,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1044 return client; 1110 return client;
1045 } 1111 }
1046 1112
1047 private void RemoveClient(LLUDPClient udpClient) 1113 private void RemoveClient(IClientAPI client)
1048 { 1114 {
1049 // Remove this client from the scene 1115 client.IsLoggingOut = true;
1050 IClientAPI client; 1116 Util.FireAndForget(o => client.Close());
1051 if (m_scene.TryGetClient(udpClient.AgentID, out client))
1052 {
1053 client.IsLoggingOut = true;
1054 client.Close(false);
1055 }
1056 } 1117 }
1057 1118
1058 private void IncomingPacketHandler() 1119 private void IncomingPacketHandler()
@@ -1161,6 +1222,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1161 // client. m_packetSent will be set to true if a packet is sent 1222 // client. m_packetSent will be set to true if a packet is sent
1162 m_scene.ForEachClient(clientPacketHandler); 1223 m_scene.ForEachClient(clientPacketHandler);
1163 1224
1225 m_currentOutgoingClient = null;
1226
1164 // If nothing was sent, sleep for the minimum amount of time before a 1227 // If nothing was sent, sleep for the minimum amount of time before a
1165 // token bucket could get more tokens 1228 // token bucket could get more tokens
1166 if (!m_packetSent) 1229 if (!m_packetSent)
@@ -1177,18 +1240,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1177 Watchdog.RemoveThread(); 1240 Watchdog.RemoveThread();
1178 } 1241 }
1179 1242
1180 private void ClientOutgoingPacketHandler(IClientAPI client) 1243 protected void ClientOutgoingPacketHandler(IClientAPI client)
1181 { 1244 {
1245 m_currentOutgoingClient = client;
1246
1182 try 1247 try
1183 { 1248 {
1184 if (client is LLClientView) 1249 if (client is LLClientView)
1185 { 1250 {
1186 LLUDPClient udpClient = ((LLClientView)client).UDPClient; 1251 LLClientView llClient = (LLClientView)client;
1252 LLUDPClient udpClient = llClient.UDPClient;
1187 1253
1188 if (udpClient.IsConnected) 1254 if (udpClient.IsConnected)
1189 { 1255 {
1190 if (m_resendUnacked) 1256 if (m_resendUnacked)
1191 HandleUnacked(udpClient); 1257 HandleUnacked(llClient);
1192 1258
1193 if (m_sendAcks) 1259 if (m_sendAcks)
1194 SendAcks(udpClient); 1260 SendAcks(udpClient);
@@ -1204,8 +1270,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1204 } 1270 }
1205 catch (Exception ex) 1271 catch (Exception ex)
1206 { 1272 {
1207 m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + 1273 m_log.Error(
1208 " threw an exception: " + ex.Message, ex); 1274 string.Format("[LLUDPSERVER]: OutgoingPacketHandler iteration for {0} threw ", client.Name), ex);
1209 } 1275 }
1210 } 1276 }
1211 1277
@@ -1231,11 +1297,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1231 { 1297 {
1232 nticks++; 1298 nticks++;
1233 watch1.Start(); 1299 watch1.Start();
1300 m_currentOutgoingClient = client;
1301
1234 try 1302 try
1235 { 1303 {
1236 if (client is LLClientView) 1304 if (client is LLClientView)
1237 { 1305 {
1238 LLUDPClient udpClient = ((LLClientView)client).UDPClient; 1306 LLClientView llClient = (LLClientView)client;
1307 LLUDPClient udpClient = llClient.UDPClient;
1239 1308
1240 if (udpClient.IsConnected) 1309 if (udpClient.IsConnected)
1241 { 1310 {
@@ -1244,7 +1313,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1244 nticksUnack++; 1313 nticksUnack++;
1245 watch2.Start(); 1314 watch2.Start();
1246 1315
1247 HandleUnacked(udpClient); 1316 HandleUnacked(llClient);
1248 1317
1249 watch2.Stop(); 1318 watch2.Stop();
1250 avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack); 1319 avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack);
@@ -1315,23 +1384,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1315 1384
1316 #endregion 1385 #endregion
1317 1386
1318 private void ProcessInPacket(object state) 1387 private void ProcessInPacket(IncomingPacket incomingPacket)
1319 { 1388 {
1320 IncomingPacket incomingPacket = (IncomingPacket)state;
1321 Packet packet = incomingPacket.Packet; 1389 Packet packet = incomingPacket.Packet;
1322 LLUDPClient udpClient = incomingPacket.Client; 1390 LLClientView client = incomingPacket.Client;
1323 IClientAPI client;
1324 1391
1325 // Sanity check 1392 if (client.IsActive)
1326 if (packet == null || udpClient == null)
1327 { 1393 {
1328 m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"", 1394 m_currentIncomingClient = client;
1329 packet, udpClient);
1330 }
1331 1395
1332 // Make sure this client is still alive
1333 if (m_scene.TryGetClient(udpClient.AgentID, out client))
1334 {
1335 try 1396 try
1336 { 1397 {
1337 // Process this packet 1398 // Process this packet
@@ -1346,21 +1407,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1346 catch (Exception e) 1407 catch (Exception e)
1347 { 1408 {
1348 // Don't let a failure in an individual client thread crash the whole sim. 1409 // Don't let a failure in an individual client thread crash the whole sim.
1349 m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type); 1410 m_log.Error(
1350 m_log.Error(e.Message, e); 1411 string.Format(
1412 "[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw ",
1413 client.Name, packet.Type),
1414 e);
1415 }
1416 finally
1417 {
1418 m_currentIncomingClient = null;
1351 } 1419 }
1352 } 1420 }
1353 else 1421 else
1354 { 1422 {
1355 m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID); 1423 m_log.DebugFormat(
1424 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
1425 packet.Type, client.Name, m_scene.RegionInfo.RegionName);
1356 } 1426 }
1357 } 1427 }
1358 1428
1359 protected void LogoutHandler(IClientAPI client) 1429 protected void LogoutHandler(IClientAPI client)
1360 { 1430 {
1361 client.SendLogoutPacket(); 1431 client.SendLogoutPacket();
1362 if (client.IsActive) 1432 if (!client.IsLoggingOut)
1363 RemoveClient(((LLClientView)client).UDPClient); 1433 RemoveClient(client);
1364 } 1434 }
1365 } 1435 }
1366} 1436}