void HandleTimeSyncResponse(TimeSyncResponse timeSyncResponse) { if (!_pendingTimeSyncRequests.ContainsKey(timeSyncResponse.SequenceIndex)) { return; } uint serverTimeAtSent = _pendingTimeSyncRequests.LookupByKey(timeSyncResponse.SequenceIndex); _pendingTimeSyncRequests.Remove(timeSyncResponse.SequenceIndex); // time it took for the request to travel to the client, for the client to process it and reply and for response to travel back to the server. // we are going to make 2 assumptions: // 1) we assume that the request processing time equals 0. // 2) we assume that the packet took as much time to travel from server to client than it took to travel from client to server. uint roundTripDuration = Time.GetMSTimeDiff(serverTimeAtSent, timeSyncResponse.GetReceivedTime()); uint lagDelay = roundTripDuration / 2; /* * clockDelta = serverTime - clientTime * where * serverTime: time that was displayed on the clock of the SERVER at the moment when the client processed the SMSG_TIME_SYNC_REQUEST packet. * clientTime: time that was displayed on the clock of the CLIENT at the moment when the client processed the SMSG_TIME_SYNC_REQUEST packet. * * Once clockDelta has been computed, we can compute the time of an event on server clock when we know the time of that same event on the client clock, * using the following relation: * serverTime = clockDelta + clientTime */ long clockDelta = (long)(serverTimeAtSent + lagDelay) - (long)timeSyncResponse.ClientTime; _timeSyncClockDeltaQueue.PushFront(Tuple.Create(clockDelta, roundTripDuration)); ComputeNewClockDelta(); }
private void HandleErroneousTimeSyncRequest(IBeaconSendingContext context, TimeSyncResponse response) { // if this is the initial sync try, we have to initialize the time provider // in every other case we keep the previous setting if (IsInitialTimeSync) { context.InitializeTimeSync(0, context.IsTimeSyncSupported); } if (BeaconSendingResponseUtil.IsTooManyRequestsResponse(response)) { // server is currently overloaded, change to CaptureOff state temporarily context.NextState = new BeaconSendingCaptureOffState(response.GetRetryAfterInMilliseconds()); } else if (context.IsTimeSyncSupported) { // in case of time sync failure when it's supported, go to capture off state context.NextState = new BeaconSendingCaptureOffState(); } else { // otherwise set the next state based on the configuration SetNextState(context); } }
public void StateTransitionToCaptureOffIsMadeIfTooManyRequestsResponseIsReceived() { // given var responseHeaders = new Dictionary <string, List <string> > { { Response.ResponseKeyRetryAfter, new List <string> { "456" } } }; var response = new TimeSyncResponse(Substitute.For <ILogger>(), string.Empty, Response.HttpTooManyRequests, responseHeaders); httpClient.SendTimeSyncRequest().Returns(response); context.IsTimeSyncSupported.Returns(true); context.IsCaptureOn.Returns(true); AbstractBeaconSendingState capturedState = null; context.NextState = Arg.Do <AbstractBeaconSendingState>(x => capturedState = x); var target = new BeaconSendingTimeSyncState(true); // when target.Execute(context); // then context.ReceivedWithAnyArgs(1).NextState = null; Assert.That(capturedState, Is.Not.Null); Assert.That(capturedState, Is.InstanceOf <BeaconSendingCaptureOffState>()); Assert.That(((BeaconSendingCaptureOffState)capturedState).sleepTimeInMilliseconds, Is.EqualTo(456 * 1000)); }
public void TimeSyncRequetsAreRetried() { // given var erroneousResponse = new TimeSyncResponse(Substitute.For <ILogger>(), string.Empty, Response.HttpBadRequest, new Dictionary <string, List <string> >()); httpClient.SendTimeSyncRequest().Returns( // request 1 fails 2 times x => erroneousResponse, x => erroneousResponse, x => CreateValidTimeResponse(currentTime, 10), // request 2 fails 1 time x => erroneousResponse, x => CreateValidTimeResponse(currentTime, 10), // request 3 fails 4 times x => erroneousResponse, x => erroneousResponse, x => erroneousResponse, x => erroneousResponse, x => CreateValidTimeResponse(currentTime, 10), // request 4 fails 0 times x => CreateValidTimeResponse(currentTime, 10), // request 5 fails 1 time x => erroneousResponse, x => CreateValidTimeResponse(currentTime, 10) ); // when var target = new BeaconSendingTimeSyncState(); target.Execute(context); // then httpClient.Received(13).SendTimeSyncRequest(); }
public void InitCompleteIsNotCalledForNonInitialRequest() { // given var erroneousResponse = new TimeSyncResponse(Substitute.For <ILogger>(), string.Empty, Response.HttpBadRequest, new Dictionary <string, List <string> >()); httpClient.SendTimeSyncRequest().Returns(erroneousResponse); // alwasys return invalid response // when var target = new BeaconSendingTimeSyncState(); target.Execute(context); // then context.DidNotReceive().InitCompleted(Arg.Any <bool>()); }
void HandleTimeSyncResponse(TimeSyncResponse packet) { Log.outDebug(LogFilter.Network, "CMSG_TIME_SYNC_RESP"); if (packet.SequenceIndex != _player.m_timeSyncQueue.FirstOrDefault()) { Log.outError(LogFilter.Network, "Wrong time sync counter from player {0} (cheater?)", _player.GetName()); } Log.outDebug(LogFilter.Network, "Time sync received: counter {0}, client ticks {1}, time since last sync {2}", packet.SequenceIndex, packet.ClientTime, packet.ClientTime - _player.m_timeSyncClient); uint ourTicks = packet.ClientTime + (Time.GetMSTime() - _player.m_timeSyncServer); // diff should be small Log.outDebug(LogFilter.Network, "Our ticks: {0}, diff {1}, latency {2}", ourTicks, ourTicks - packet.ClientTime, GetLatency()); _player.m_timeSyncClient = packet.ClientTime; _player.m_timeSyncQueue.Pop(); }
public void SleepTimeIsDoubledAndResetAfterSuccess() { // given var erroneousResponse = new TimeSyncResponse(Substitute.For <ILogger>(), string.Empty, Response.HttpBadRequest, new Dictionary <string, List <string> >()); httpClient.SendTimeSyncRequest().Returns( // request 1 fails 2 times x => erroneousResponse, x => erroneousResponse, x => erroneousResponse, x => erroneousResponse, x => erroneousResponse, x => CreateValidTimeResponse(currentTime, 10), // request 2 fails 1 time x => erroneousResponse, // other requets do not fail x => CreateValidTimeResponse(currentTime, 10), x => CreateValidTimeResponse(currentTime, 10), x => CreateValidTimeResponse(currentTime, 10), x => CreateValidTimeResponse(currentTime, 10) ); // when var target = new BeaconSendingTimeSyncState(); target.Execute(context); // then httpClient.Received(11).SendTimeSyncRequest(); context.Received(6).Sleep(Arg.Any <int>()); Received.InOrder(() => { // sleeps for first request context.Sleep(1000); // start with 1 sec context.Sleep(2000); // double context.Sleep(4000); // double context.Sleep(8000); // double context.Sleep(16000); // double // sleeps for second request context.Sleep(1000); // start with 1 sec again }); }