00001
00025 #include "vector.h"
00026 #include "timesync.h"
00027 #include "iothread.h"
00028 #include "message.h"
00029 #include "vector.h"
00030 #include "net.h"
00031 #include <assert.h>
00032 #include <math.h>
00033 #ifndef NDEBUG
00034 #include <stdio.h>
00035 #endif
00036 #ifndef WIN32
00037 #include <sys/time.h>
00038 #include <sys/types.h>
00039 #include <unistd.h>
00040 #endif
00041 #include <SDL.h>
00042 #include <SDL_thread.h>
00043
00044 Sint32 timeDelta;
00045 int timeSyncState = TIMESYNC_IDLE;
00046 TimeSample timeSyncResults;
00047
00052 static SDL_Thread *thread = NULL;
00053
00057 static int tsyncSock;
00058
00065 #define REQ_SAMPLES 16
00066
00072 #define INC_SAMPLES 4
00073
00081 #define MAX_SAMPLES 32
00082
00090 static void ComputeAverages(Vector *samples) {
00091 double delta = 0, latency = 0;
00092 TimeSample *sample = (TimeSample*)samples->array;
00093 unsigned int loop;
00094 if (samples->items) {
00095
00096 for (loop = 0; loop < samples->items; loop++, sample++) {
00097
00098 delta += sample->delta;
00099 latency += sample->latency;
00100 }
00101
00102 timeSyncResults.delta = delta / (double)samples->items;
00103 timeSyncResults.latency = latency / (double)samples->items;
00104 }
00105 else {
00106 timeSyncResults.delta = timeSyncResults.latency = 0.0;
00107 }
00108 }
00109
00118 static double ComputeStdDeviation(Vector *samples) {
00119 double delta = 0;
00120 TimeSample *sample = (TimeSample*)samples->array;
00121 unsigned int loop;
00122
00123 for (loop = 0; loop < samples->items; loop++, sample++) {
00124
00125 delta = (timeSyncResults.delta - sample->delta) *
00126 (timeSyncResults.delta - sample->delta);
00127 }
00128
00129 return sqrt(delta / (double)(samples->items - 1));
00130 }
00131
00144 static Bool GetSamples(Vector *samples, SocketAddr *dest, int sock,
00145 int reqSamples) {
00146 fd_set fds;
00147 SocketAddr origin;
00148 TimeSample *lastSample;
00149 int loop;
00150 Uint32 sentTime, recvTime;
00151 Uint8 buff[9];
00152 origin.length = sizeof(struct sockaddr_in6);
00153 FD_ZERO(&fds);
00154
00155 loop = (reqSamples << 1) - samples->items;
00156 while ((loop > 0) && !IsCancelationRequested()) {
00157 int gotTime;
00158
00159 struct timeval tv = { 0, 500000 };
00160
00161 SDL_Delay(50);
00162
00163 sentTime = SDL_GetTicks();
00164
00165 buff[0] = localPlayer;
00166 MSG_WRITE_32C(buff, 1, sentTime);
00167
00168 if (sendto(sock, buff, 5, 0, &(dest->addr), dest->length) != 5) {
00169
00170 timeSyncState = TIMESYNC_ERROR;
00171 return FALSE;
00172 }
00173 GetSamples_select:
00174 FD_SET(sock, &fds);
00175
00176 if (select(sock + 1, &fds, NULL, &fds, &tv) <= 0) {
00177
00178 continue;
00179 }
00180
00181 if ((recvfrom(sock, buff, 9, 0, &origin.addr,
00182 &origin.length) != 9) || !EqualAddresses(&origin, dest)) {
00183
00184 goto GetSamples_select;
00185 }
00186
00187 recvTime = SDL_GetTicks();
00188
00189
00190 MSG_READ_32C(buff, 1, gotTime);
00191 if ((localPlayer != buff[0]) || (gotTime != sentTime)) {
00192
00193 goto GetSamples_select;
00194 }
00195
00196 MSG_READ_32C(buff, 5, gotTime);
00197 lastSample = VectorAdd(samples);
00198 lastSample->delta = (double)(gotTime - recvTime) +
00199 (lastSample->latency = (double)(recvTime - sentTime) / 2.0);
00200
00201 loop--;
00202 }
00203
00204 return TRUE;
00205 }
00206
00215 static void RemoveBadSamples(Vector *samples) {
00216 double stdDev, upper, lower;
00217 TimeSample *sample = (TimeSample*)samples->array;
00218 unsigned int loop = 0;
00219
00220 ComputeAverages(samples);
00221
00222 stdDev = ComputeStdDeviation(samples);
00223
00224 lower = timeSyncResults.delta - stdDev - 1.0;
00225
00226 upper = timeSyncResults.delta + stdDev + 1.0;
00227
00228 while (loop < samples->items) {
00229
00230 if ((sample->delta > upper) || (sample->delta < lower)) {
00231
00232 VectorRemove(samples, loop);
00233 }
00234 else {
00235
00236 sample++;
00237 loop++;
00238 }
00239 }
00240 }
00241
00242 extern Uint32 frameTime;
00243
00251 static void ClientSync(void *ignore) {
00252 Vector samples;
00253 SocketAddr addr;
00254 int sock, time;
00255 unsigned int required;
00256
00257
00258 samples.destructOp = NULL;
00259 samples.itemSize = sizeof(TimeSample);
00260 if (!VectorInit(&samples, samples.minSize = 32)) {
00261
00262 timeSyncState = TIMESYNC_ERROR;
00263 return;
00264 }
00265
00266 assert((outgoingAddr.addr.sa_family == AF_INET) ||
00267 (outgoingAddr.addr.sa_family == AF_INET6));
00268
00269 if ((addr.addr.sa_family = outgoingAddr.addr.sa_family) == AF_INET) {
00270
00271 addr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
00272
00273 addr.ipv4.sin_port = htons(PORT_CTSYNC);
00274 }
00275
00276 else {
00278
00279 addr.ipv6.sin6_port = htons(PORT_CTSYNC);
00280 }
00281
00282 if ((sock = UnicastSocket(&addr, TRUE)) == -1) {
00283
00284 timeSyncState = TIMESYNC_ERROR;
00285 goto ClientSync_end;
00286 }
00287
00288 addr = outgoingAddr;
00289 if (addr.addr.sa_family == AF_INET) {
00290
00291 addr.ipv4.sin_port = htons(PORT_STSYNC);
00292 }
00293
00294 else {
00295
00296 addr.ipv6.sin6_port = htons(PORT_STSYNC);
00297 }
00298
00299 required = REQ_SAMPLES;
00300
00301 do {
00302
00303 if (!GetSamples(&samples, &addr, sock, required)) {
00304
00305 timeSyncState = TIMESYNC_ERROR;
00306 goto ClientSync_end;
00307 }
00308
00309 if (required < MAX_SAMPLES) {
00310
00311 RemoveBadSamples(&samples);
00312 }
00313
00314 required += INC_SAMPLES;
00315 } while ((samples.items < required) && (required <= MAX_SAMPLES)
00316 && !IsCancelationRequested());
00317
00318 ComputeAverages(&samples);
00319
00320 timeDelta = (Sint32)timeSyncResults.delta;
00321
00322 time = SDL_GetTicks() + timeDelta;
00323 frameTime = time - (time % FRAME_DURATION) + FRAME_DURATION;
00324
00325 if (samples.items < required) {
00326
00327 timeSyncState = TIMESYNC_POOR;
00328 }
00329 else {
00330
00331 timeSyncState = TIMESYNC_FINISHED;
00332 }
00333 ClientSync_end:
00334 #if !defined(NDEBUG) && !defined(GETTEXT)
00335 {
00336 int error;
00337 printf("Time synchronization ended ");
00338 switch (timeSyncState) {
00339 case TIMESYNC_FINISHED:
00340 printf("successfully.");
00341 break;
00342 case TIMESYNC_POOR:
00343 printf("with poor quality results.");
00344 break;
00345 case TIMESYNC_ERROR:
00346 printf("on an error.");
00347 if ((error = GetNetErrorVal()) != 0) {
00348 #ifdef USE_GETTEXT
00349 printf("\n\tNetwork error: %ls\n", GetNetErrorString(error));
00350 #else
00351 printf("\n\tNetwork error: %s\n", GetNetErrorString(error));
00352 #endif
00353 }
00354 return;
00355 default:
00356 printf("with undefined state 0x%X.\n", timeSyncState);
00357 return;
00358 }
00359 printf("\n\tsamples = %d\n\tdelta = %lfms\n\tlatency = %lfms\n",
00360 samples.items, timeSyncResults.delta, timeSyncResults.latency);
00361 #ifdef WIN32
00362 fflush(stdout);
00363 #endif
00364 }
00365 #endif
00366
00367 CloseSocket(sock);
00368
00369 VectorDestroy(&samples);
00370 }
00371
00372 void StartClientTimeSync() {
00373 timeSyncState = TIMESYNC_INPROG;
00374 QueueOperation(ClientSync, NULL);
00375 }
00376
00382 static int ServerTimeSyncThread(void *ignore) {
00383 SocketAddr origin;
00384 int error = 0;
00385 Uint32 now;
00386 Uint8 buff[9];
00387
00388 do {
00389
00390 origin.length = sizeof(struct sockaddr_in6);
00391
00392 if (recvfrom(tsyncSock, buff, 5, 0, &origin.addr, &origin.length) == 5) {
00393
00394 if (ValidateClient(&origin, buff[0])) {
00395
00396 now = SDL_GetTicks();
00397 MSG_WRITE_32C(buff, 5, now);
00398
00399 if (origin.addr.sa_family == AF_INET) {
00400
00401 origin.ipv4.sin_port = htons(PORT_CTSYNC);
00402 }
00403
00404 else {
00405
00406 origin.ipv6.sin6_port = htons(PORT_CTSYNC);
00407 }
00408
00409 sendto(tsyncSock, buff, 9, 0, &origin.addr, origin.length);
00410 }
00411
00412 error = 0;
00413 }
00414 else {
00415
00416 error = GetNetErrorVal();
00417 }
00418 } while ((tsyncSock != -1) && ((error == 0) || (error == ECONNREFUSED)));
00419 #ifndef NDEBUG
00420 if ((tsyncSock != -1) && error) {
00421 #ifndef WIN32
00422 #ifdef USE_GETTEXT
00423 fwprintf(stderr, L"Server time synchronization ended on error: %ls\n",
00424 GetNetErrorString(error));
00425 #else
00426 fprintf(stderr, "Server time synchronization ended on error: %s\n",
00427 GetNetErrorString(error));
00428 #endif
00429 #endif
00430 }
00431 #endif
00432 return 0;
00433 }
00434
00435 Bool StartServerTimeSync() {
00436 SocketAddr addr;
00437
00439 addr.ipv4.sin_family = AF_INET;
00440 addr.ipv4.sin_port = htons(PORT_STSYNC);
00441 addr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
00442
00443 if ((tsyncSock = UnicastSocket(&addr, TRUE)) == -1) {
00444
00445 return FALSE;
00446 }
00447
00448 thread = SDL_CreateThread(ServerTimeSyncThread, NULL);
00449 return TRUE;
00450 }
00451
00452 void StopServerTimeSync() {
00453 CloseSocket(tsyncSock);
00454 timeSyncState = TIMESYNC_IDLE;
00455 }
00456