aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin Clarke Casey2008-10-17 20:14:31 +0000
committerJustin Clarke Casey2008-10-17 20:14:31 +0000
commit90d69a05233206e1bce5896405bd34545bcd6b40 (patch)
tree0a64d6a0142db4bff442dd25a7d1468d7c382707
parentAdd two missing settings to OpenSim.ini.example. (diff)
downloadopensim-SC-90d69a05233206e1bce5896405bd34545bcd6b40.zip
opensim-SC-90d69a05233206e1bce5896405bd34545bcd6b40.tar.gz
opensim-SC-90d69a05233206e1bce5896405bd34545bcd6b40.tar.bz2
opensim-SC-90d69a05233206e1bce5896405bd34545bcd6b40.tar.xz
* close two potential race conditions where a new asynchronous UDP recieve could overwrite an existing endpoint that had not yet been used by the previous thread
* in practice these race conditions were probably pretty rare
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs122
1 files changed, 53 insertions, 69 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index 26a77e4..01a4dd6 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -58,10 +58,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
58 protected byte[] ZeroBuffer = new byte[8192]; 58 protected byte[] ZeroBuffer = new byte[8192];
59 59
60 /// <value> 60 /// <value>
61 /// The endpoint of a sender of a particular packet. The port is changed by the various socket receive methods 61 /// This is an endpoint that is reused where we don't need to protect the information from potentially
62 /// being stomped on by other threads.
62 /// </value> 63 /// </value>
63 protected EndPoint reusedEpSender = new IPEndPoint(IPAddress.Any, 0); 64 protected EndPoint reusedEpSender = new IPEndPoint(IPAddress.Any, 0);
64 protected EndPoint reusedEpProxy; 65
65 protected int proxyPortOffset; 66 protected int proxyPortOffset;
66 67
67 protected AsyncCallback ReceivedData; 68 protected AsyncCallback ReceivedData;
@@ -178,11 +179,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
178 Packet packet = null; 179 Packet packet = null;
179 int numBytes = 1; 180 int numBytes = 1;
180 bool ok = false; 181 bool ok = false;
181 reusedEpSender = new IPEndPoint(IPAddress.Any, 0); 182 EndPoint epSender = new IPEndPoint(IPAddress.Any, 0);
182 183
183 try 184 try
184 { 185 {
185 numBytes = m_socket.EndReceiveFrom(result, ref reusedEpSender); 186 numBytes = m_socket.EndReceiveFrom(result, ref epSender);
186 ok = true; 187 ok = true;
187 } 188 }
188 catch (SocketException e) 189 catch (SocketException e)
@@ -218,12 +219,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
218 for (z = numBytes ; z < RecvBuffer.Length ; z++) 219 for (z = numBytes ; z < RecvBuffer.Length ; z++)
219 RecvBuffer[z] = 0; 220 RecvBuffer[z] = 0;
220 221
221 reusedEpProxy = reusedEpSender;
222 if (proxyPortOffset != 0)
223 {
224 reusedEpSender = ProxyCodec.DecodeProxyMessage(RecvBuffer, ref numBytes);
225 }
226
227 int packetEnd = numBytes - 1; 222 int packetEnd = numBytes - 1;
228 223
229 try 224 try
@@ -242,30 +237,48 @@ namespace OpenSim.Region.ClientStack.LindenUDP
242 { 237 {
243 m_log.Debug("[CLIENT]: " + e); 238 m_log.Debug("[CLIENT]: " + e);
244 } 239 }
240 }
241
242 EndPoint epProxy = null;
243
244 // If we've received a use circuit packet, then we need to decode an endpoint proxy, if one exists, before
245 // allowing the RecvBuffer to be overwritten by the next packet.
246 if (packet.Type == PacketType.UseCircuitCode)
247 {
248 epProxy = epSender;
249 if (proxyPortOffset != 0)
250 {
251 epSender = ProxyCodec.DecodeProxyMessage(RecvBuffer, ref numBytes);
252 }
245 } 253 }
246 254
247 BeginReceive(); 255 BeginReceive();
248 256
249 if (packet != null) 257 if (packet != null)
250 ProcessInPacket(packet); 258 {
259 if (packet.Type == PacketType.UseCircuitCode)
260 AddNewClient((UseCircuitCodePacket)packet, epSender, epProxy);
261 else
262 ProcessInPacket(packet, epSender);
263 }
251 } 264 }
252 265
253 /// <summary> 266 /// <summary>
254 /// Process a successfully received packet. We pass the packet on to the LLPacketServer 267 /// Process a successfully received packet.
255 /// except in the case that the packet is UseCircuitCode. In that case we set up the circuit code instead.
256 /// </summary> 268 /// </summary>
257 /// <param name="packet"></param> 269 /// <param name="packet"></param>
258 protected virtual void ProcessInPacket(Packet packet) 270 /// <param name="epSender"></param>
271 protected virtual void ProcessInPacket(Packet packet, EndPoint epSender)
259 { 272 {
260 try 273 try
261 { 274 {
262 // do we already have a circuit for this endpoint 275 // do we already have a circuit for this endpoint
263 uint circuit; 276 uint circuit;
264
265 bool ret; 277 bool ret;
278
266 lock (clientCircuits) 279 lock (clientCircuits)
267 { 280 {
268 ret = clientCircuits.TryGetValue(reusedEpSender, out circuit); 281 ret = clientCircuits.TryGetValue(epSender, out circuit);
269 } 282 }
270 283
271 if (ret) 284 if (ret)
@@ -275,21 +288,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
275 288
276 m_packetServer.InPacket(circuit, packet); 289 m_packetServer.InPacket(circuit, packet);
277 } 290 }
278 else if (packet.Type == PacketType.UseCircuitCode)
279 {
280 UseCircuitCodePacket p = (UseCircuitCodePacket)packet;
281
282 AddNewClient(p);
283
284 // Ack the first UseCircuitCode packet
285 PacketAckPacket ack_it = (PacketAckPacket)PacketPool.Instance.GetPacket(PacketType.PacketAck);
286 // TODO: don't create new blocks if recycling an old packet
287 ack_it.Packets = new PacketAckPacket.PacketsBlock[1];
288 ack_it.Packets[0] = new PacketAckPacket.PacketsBlock();
289 ack_it.Packets[0].ID = packet.Header.Sequence;
290 ack_it.Header.Reliable = false;
291 SendPacketTo(ack_it.ToBytes(), ack_it.ToBytes().Length, SocketFlags.None, p.CircuitCode.Code);
292 }
293 } 291 }
294 catch (Exception e) 292 catch (Exception e)
295 { 293 {
@@ -319,7 +317,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
319 } 317 }
320 catch (Exception a) 318 catch (Exception a)
321 { 319 {
322 m_log.Info("[UDPSERVER]: " + a); 320 m_log.Error("[UDPSERVER]: " + a);
323 } 321 }
324 322
325 try 323 try
@@ -356,61 +354,47 @@ namespace OpenSim.Region.ClientStack.LindenUDP
356 /// Add a new client circuit. 354 /// Add a new client circuit.
357 /// </summary> 355 /// </summary>
358 /// <param name="packet"></param> 356 /// <param name="packet"></param>
359 protected virtual void AddNewClient(UseCircuitCodePacket useCircuit) 357 /// <param name="epSender"></param>
358 /// <param name="epProxy"></param>
359 protected virtual void AddNewClient(UseCircuitCodePacket useCircuit, EndPoint epSender, EndPoint epProxy)
360 { 360 {
361 //Slave regions don't accept new clients 361 //Slave regions don't accept new clients
362 if (m_localScene.Region_Status != RegionStatus.SlaveScene) 362 if (m_localScene.Region_Status != RegionStatus.SlaveScene)
363 { 363 {
364 m_log.DebugFormat(
365 "[CLIENT]: Adding new circuit for agent {0}, circuit code {1}",
366 useCircuit.CircuitCode.ID, useCircuit.CircuitCode.Code);
367
368 // Copy the current reusedEpSender and reusedEpProxy to store in the maps and hashes,
369 // since the reused ones will change on the next packet receipt.
370 IPEndPoint reusedIpEpSender = (IPEndPoint)reusedEpSender;
371 EndPoint epSender = new IPEndPoint(reusedIpEpSender.Address, reusedIpEpSender.Port);
372
373 IPEndPoint reusedIpEpPorxy = (IPEndPoint)reusedEpProxy;
374 EndPoint epProxy = new IPEndPoint(reusedIpEpPorxy.Address, reusedIpEpPorxy.Port);
375
376 lock (clientCircuits) 364 lock (clientCircuits)
377 { 365 {
378 if (!clientCircuits.ContainsKey(epSender)) 366 if (!clientCircuits.ContainsKey(epSender))
379 {
380 clientCircuits.Add(epSender, useCircuit.CircuitCode.Code);
381 }
382 else
383 { 367 {
384 m_log.Error( 368 m_log.DebugFormat(
385 "[CLIENT]: clientCircuits already contains entry for user " 369 "[CLIENT]: Adding new circuit for agent {0}, circuit code {1}",
386 + useCircuit.CircuitCode.Code + ". NOT adding."); 370 useCircuit.CircuitCode.ID, useCircuit.CircuitCode.Code);
371
372 clientCircuits.Add(epSender, useCircuit.CircuitCode.Code);
387 } 373 }
388 } 374 }
389 375
390 // This doesn't need locking as it's synchronized data 376 // This doesn't need locking as it's synchronized data
391 if (!clientCircuits_reverse.ContainsKey(useCircuit.CircuitCode.Code)) 377 if (!clientCircuits_reverse.ContainsKey(useCircuit.CircuitCode.Code))
392 clientCircuits_reverse.Add(useCircuit.CircuitCode.Code, epSender); 378 clientCircuits_reverse.Add(useCircuit.CircuitCode.Code, epSender);
393 else
394 m_log.Error(
395 "[CLIENT]: clientCurcuits_reverse already contains entry for user "
396 + useCircuit.CircuitCode.Code + ". NOT adding.");
397 379
398 lock (proxyCircuits) 380 lock (proxyCircuits)
399 { 381 {
400 if (!proxyCircuits.ContainsKey(useCircuit.CircuitCode.Code)) 382 if (!proxyCircuits.ContainsKey(useCircuit.CircuitCode.Code))
401 proxyCircuits.Add(useCircuit.CircuitCode.Code, epProxy); 383 proxyCircuits.Add(useCircuit.CircuitCode.Code, epProxy);
402 else
403 m_log.Error(
404 "[CLIENT]: proxyCircuits already contains entry for user "
405 + useCircuit.CircuitCode.Code + ". NOT adding.");
406 } 384 }
407 385
408 if (!PacketServer.AddNewClient(epSender, useCircuit, m_assetCache, m_circuitManager, epProxy)) 386 PacketServer.AddNewClient(epSender, useCircuit, m_assetCache, m_circuitManager, epProxy);
409 m_log.ErrorFormat( 387 }
410 "[CLIENT]: A circuit already existed for agent {0}, circuit {1}", 388
411 useCircuit.CircuitCode.ID, useCircuit.CircuitCode.Code); 389 // Ack the UseCircuitCode packet
412 } 390 PacketAckPacket ack_it = (PacketAckPacket)PacketPool.Instance.GetPacket(PacketType.PacketAck);
413 391 // TODO: don't create new blocks if recycling an old packet
392 ack_it.Packets = new PacketAckPacket.PacketsBlock[1];
393 ack_it.Packets[0] = new PacketAckPacket.PacketsBlock();
394 ack_it.Packets[0].ID = useCircuit.Header.Sequence;
395 ack_it.Header.Reliable = false;
396 SendPacketTo(ack_it.ToBytes(), ack_it.ToBytes().Length, SocketFlags.None, useCircuit.CircuitCode.Code);
397
414 PacketPool.Instance.ReturnPacket(useCircuit); 398 PacketPool.Instance.ReturnPacket(useCircuit);
415 } 399 }
416 400