private static void listenerThreadProc() { staticLogMessage(new MessageEvent("Network Clock listener thread is alive", 1, MessageEvent.MessageTypes.Log, MessageEvent.MessageCategories.Networking)); while (true) { // Wait for a datagram from the udpClient. // This makes use of a temporary local reference to udpClient so that we can be sure // that even if the static udpClient member is changed when we don't hold the static lock // we will at least run the callback on the correct instance of udpClient. // (I didn't want to lock the receive callback on staticLockObj, because the callback may // take arbitrarily long to return, and I don't want to be locked out of other static activities like // shutting down the listener. System.Net.IPEndPoint remoteEnd = null; IAsyncResult result; byte[] received; UdpClient udpClientNonstatic; lock (staticLockObj) { udpClientNonstatic = udpClient; result = udpClient.BeginReceive(null, null); } received = udpClientNonstatic.EndReceive(result, ref remoteEnd); if (received.Length != NetworkClockDatagram.datagramByteLength) { staticLogMessage(new MessageEvent("Received wrong sized (" + received.Length + ") datagram. Dropping.", 1, MessageEvent.MessageTypes.Error, MessageEvent.MessageCategories.Networking)); continue; } NetworkClockDatagram ndgram = new NetworkClockDatagram(received); #if DEBUG staticLogMessage(new MessageEvent("Received network clock datagram " + ndgram.ToString(), 2, MessageEvent.MessageTypes.Debug, MessageEvent.MessageCategories.Networking)); #endif if (ndgram.DatagramCount != lastNGramID + 1) { staticLogMessage(new MessageEvent("Warning! Received network clock datagram #" + ndgram.DatagramCount + ", expected #" + (lastNGramID + 1) + ".", 0, MessageEvent.MessageTypes.Warning, MessageEvent.MessageCategories.Networking)); } lastNGramID = ndgram.DatagramCount; NetworkClockProvider pr = null; // Pull designated provider out of provider's dictionary (locked on staticLockObj since // we are accessing static providers dictionary) // Will leave pr as null if no such ClockID listener exists. // Will throw an exception if clockID does exist, but listener is null. lock (staticLockObj) { if (providers.ContainsKey(ndgram.ClockID)) { pr = providers[ndgram.ClockID]; if (pr == null) { throw new SoftwareClockProviderException("Unexpected null network clock provider."); } } } // If provider does exist, (is not null), relay to it the latest // clock message if (pr != null) { // Thread lock on pr object lock (pr.instanceLockObj) { if (pr.isRunning) { if (!pr.receivedFirstClock) { staticLogMessage(new MessageEvent("Received first clock datagram for clockID " + Shared.clockIDToString(pr.clockID), 0, MessageEvent.MessageTypes.Routine, MessageEvent.MessageCategories.SoftwareClock)); pr.receivedFirstClock = true; } pr.reachTime(ndgram.ElaspedTime); } } } } }