diff options
author | Justin Clarke Casey | 2008-10-17 20:14:31 +0000 |
---|---|---|
committer | Justin Clarke Casey | 2008-10-17 20:14:31 +0000 |
commit | 90d69a05233206e1bce5896405bd34545bcd6b40 (patch) | |
tree | 0a64d6a0142db4bff442dd25a7d1468d7c382707 | |
parent | Add two missing settings to OpenSim.ini.example. (diff) | |
download | opensim-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.cs | 122 |
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 | ||