Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / net / unitime.cpp
blobdf520d549d1013575c9cd3c6c9ac8206d64c01a9
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2016 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdnet.h"
22 #include "nel/net/callback_client.h"
23 #include "nel/net/callback_server.h"
24 #include "nel/net/naming_client.h"
25 #include "nel/net/message.h"
27 #include "nel/net/unitime.h"
29 using namespace NLMISC;
30 using namespace std;
32 namespace NLNET
35 TTime _CUniTime::_SyncUniTime = 0;
36 TTime _CUniTime::_SyncLocalTime = 0;
37 bool _CUniTime::_Simulate = false;
39 bool _CUniTime::Sync = false;
42 void _CUniTime::setUniTime (NLMISC::TTime /* uTime */, NLMISC::TTime /* lTime */)
44 nlstop;
45 /* if (Sync)
47 TTime lt = getLocalTime ();
48 TTime delta = uTime - lTime + _SyncLocalTime - _SyncUniTime;
50 nlinfo ("_CUniTime::setUniTime(%" NL_I64 "d, %" NL_I64 "d): Resyncing delta %" NL_I64 "dms",uTime,lTime,delta);
52 else
54 nlinfo ("_CUniTime::setUniTime(%" NL_I64 "d, %" NL_I64 "d)",uTime,lTime);
55 Sync = true;
57 _SyncUniTime = uTime;
58 _SyncLocalTime = lTime;
59 */}
61 void _CUniTime::setUniTime (NLMISC::TTime /* uTime */)
63 nlstop;
64 // setUniTime (uTime, getLocalTime ());
69 TTime _CUniTime::getUniTime ()
71 nlstop;
72 return 0;
73 /* if (!Sync)
75 nlerror ("called getUniTime before calling syncUniTimeFromServer");
77 return getLocalTime () - (_SyncLocalTime - _SyncUniTime);
82 const char *_CUniTime::getStringUniTime ()
84 nlstop;
85 return getStringUniTime(_CUniTime::getUniTime());
89 const char *_CUniTime::getStringUniTime (TTime ut)
91 nlstop;
92 static char str[512];
94 uint32 ms = (uint32) (ut % 1000); // time in ms 1000ms dans 1s
95 ut /= 1000;
97 uint32 s = (uint32) (ut % 60); // time in seconds 60s dans 1mn
98 ut /= 60;
100 uint32 m = (uint32) (ut % 60); // time in minutes 60m dans 1h
101 ut /= 60;
103 uint32 h = (uint32) (ut % 9); // time in hours 9h dans 1j
104 ut /= 9;
106 uint32 day = (uint32) (ut % (8*4)); // time in days 8day dans 1month
107 ut /= 8;
109 uint32 week = (uint32) (ut % 4); // time in weeks 4week dans 1month
110 ut /= 4;
112 uint32 month = (uint32) (ut % 12); // time in months 12month dans 1year
113 ut /= 12;
115 uint year = (uint32) ut; // time in years
117 smprintf (str, 512, "%02d/%02d/%04d (week %d) %02d:%02d:%02d.%03d", day+1, month+1, year+1, week+1, h, m, s, ms);
118 return str;
121 ////////////////////////////////////////////////////////////////////////////////////////////////////
122 ////////////////////////////////////////////////////////////////////////////////////////////////////
123 /////////////// SYNCHRONISATION BETWEEN TIME SERVICE AND OTHER SERVICES ////////////////////////////
124 ////////////////////////////////////////////////////////////////////////////////////////////////////
125 ////////////////////////////////////////////////////////////////////////////////////////////////////
127 static bool GetUniversalTime;
128 static uint32 GetUniversalTimeSecondsSince1970;
129 static TTime GetUniversalTimeUniTime;
132 static void cbGetUniversalTime (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
134 nlstop;
135 // get the association between a date and unitime
136 msgin.serial (GetUniversalTimeSecondsSince1970);
137 msgin.serial (GetUniversalTimeUniTime);
138 GetUniversalTime = true;
142 /***************************************************************/
143 /******************* THE FOLLOWING CODE IS COMMENTED OUT *******/
144 /***************************************************************
145 static TCallbackItem UniTimeCallbackArray[] =
147 { "GUT", cbGetUniversalTime }
149 ***************************************************************/
151 void _CUniTime::syncUniTimeFromService (CCallbackNetBase::TRecordingState /* rec */, const CInetAddress * /* addr */)
153 nlstop;
154 /***************************************************************/
155 /******************* THE FOLLOWING CODE IS COMMENTED OUT *******/
156 /***************************************************************
157 TTime deltaAdjust, lt;
158 uint32 firstsecond, nextsecond;
159 TTime before, after, delta;
161 // create a message with type in the full text format
162 CMessage msgout ("AUT");
163 CCallbackClient server( rec, "TS.nmr" );
164 server.addCallbackArray (UniTimeCallbackArray, sizeof (UniTimeCallbackArray) / sizeof (UniTimeCallbackArray[0]));
166 if (addr == NULL)
168 CNamingClient::lookupAndConnect ("TS", server);
170 else
172 server.connect (*addr);
175 if (!server.connected()) goto error;
177 server.send (msgout);
179 // before time
180 before = CTime::getLocalTime ();
182 // receive the answer
183 GetUniversalTime = false;
184 while (!GetUniversalTime)
186 if (!server.connected()) goto error;
188 server.update ();
190 nlSleep( 0 );
193 // after, before and delta is not used. It's only for information purpose.
194 after = CTime::getLocalTime ();
195 delta = after - before;
197 nlinfo ("_CUniTime::syncUniTimeFromService(): ping:%" NL_I64 "dms, time:%ds, unitime:%" NL_I64 "dms", delta, GetUniversalTimeSecondsSince1970, GetUniversalTimeUniTime);
199 // <-- from here to the "-->" comment, the block must be executed in less than one second or an infinite loop occurs
201 // get the second
202 firstsecond = CTime::getSecondsSince1970 ();
203 nextsecond = firstsecond+1;
205 // wait the next start of the second (take 100% of CPU to be more accurate)
206 while (nextsecond != CTime::getSecondsSince1970 ())
207 nlassert (CTime::getSecondsSince1970 () <= nextsecond);
209 // -->
211 // get the local time of the beginning of the next second
212 lt = CTime::getLocalTime ();
214 if ( ! _Simulate )
216 if (abs((sint32)((TTime)nextsecond - (TTime)GetUniversalTimeSecondsSince1970)) > 10)
218 nlerror ("the time delta (between me and the Time Service) is too big (more than 10s), servers aren't NTP synchronized");
219 goto error;
222 // compute the delta between the other side and our side number of second since 1970
223 deltaAdjust = ((TTime) nextsecond - (TTime) GetUniversalTimeSecondsSince1970) * 1000;
225 // adjust the unitime to the current localtime
226 GetUniversalTimeUniTime += deltaAdjust;
228 nlinfo ("_CUniTime::syncUniTimeFromService(): rtime:%ds, runitime:%" NL_I64 "ds, rlocaltime:%" NL_I64 "d, deltaAjust:%" NL_I64 "dms", nextsecond, GetUniversalTimeUniTime, lt, deltaAdjust);
230 else
232 nlinfo ("_CUniTime::syncUniTimeFromService(): runitime:%" NL_I64 "ds, rlocaltime:%" NL_I64 "d", GetUniversalTimeUniTime, lt);
235 _CUniTime::setUniTime (GetUniversalTimeUniTime, lt);
237 server.disconnect ();
238 return;
240 error:
241 nlerror ("Time Service is not found, lost or can't synchronize universal time");
242 ***************************************************************/
248 ////////////////////////////////////////////////////////////////////////////////////////////////////
249 ////////////////////////////////////////////////////////////////////////////////////////////////////
250 /////////////// SYNCHRONISATION BETWEEN CLIENT AND SHARD ///////////////////////////////////////////
251 ////////////////////////////////////////////////////////////////////////////////////////////////////
252 ////////////////////////////////////////////////////////////////////////////////////////////////////
254 // Server part
256 static void cbServerAskUniversalTime (CMessage& /* msgin */, TSockId from, CCallbackNetBase &netbase)
258 nlstop;
259 TTime ut = _CUniTime::getUniTime ();
261 // afficher l adresse de celui qui demande
262 nlinfo("UT: Send the universal time %" NL_I64 "d to '%s'", ut, netbase.hostAddress(from).asString().c_str());
264 CMessage msgout ("GUT");
265 msgout.serial (ut);
266 netbase.send (msgout, from);
269 TCallbackItem ServerTimeServiceCallbackArray[] =
271 { "AUT", cbServerAskUniversalTime },
274 void _CUniTime::installServer (CCallbackServer *server)
276 nlstop;
277 static bool alreadyAddedCallback = false;
278 nlassert (server != NULL);
279 nlassert (!alreadyAddedCallback);
281 server->addCallbackArray (ServerTimeServiceCallbackArray, sizeof (ServerTimeServiceCallbackArray) / sizeof (ServerTimeServiceCallbackArray[0]));
282 alreadyAddedCallback = true;
285 // Client part
287 static bool GetClientUniversalTime;
288 static TTime GetClientUniversalTimeUniTime;
291 static void cbClientGetUniversalTime (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
293 nlstop;
294 // get the association between a date and unitime
295 msgin.serial (GetClientUniversalTimeUniTime);
296 GetClientUniversalTime = true;
300 /***************************************************************/
301 /******************* THE FOLLOWING CODE IS COMMENTED OUT *******/
302 /***************************************************************
303 static TCallbackItem ClientUniTimeCallbackArray[] =
305 { "GUT", cbClientGetUniversalTime }
307 ***************************************************************/
310 void _CUniTime::syncUniTimeFromServer (CCallbackClient * /* client */)
312 nlstop;
313 /***************************************************************/
314 /******************* THE FOLLOWING CODE IS COMMENTED OUT *******/
315 /***************************************************************
317 static bool alreadyAddedCallback = false;
318 nlassert (client != NULL);
320 if (!alreadyAddedCallback)
322 client->addCallbackArray (ClientUniTimeCallbackArray, sizeof (ClientUniTimeCallbackArray) / sizeof (ClientUniTimeCallbackArray[0]));
323 alreadyAddedCallback = true;
326 sint attempt = 0;
327 TTime bestdelta = 60000; // 1 minute
329 if (!client->connected ()) goto error;
331 while (attempt < 10)
333 CMessage msgout ("AUT");
335 if (!client->connected()) goto error;
337 // send the message
338 client->send (msgout);
340 // before time
341 TTime before = CTime::getLocalTime ();
343 // receive the answer
344 GetClientUniversalTime = false;
345 while (!GetClientUniversalTime)
347 if (!client->connected()) goto error;
349 client->update ();
352 TTime after = CTime::getLocalTime (), delta = after - before;
354 if (delta < 10 || delta < bestdelta)
356 bestdelta = delta;
358 _CUniTime::setUniTime (GetClientUniversalTimeUniTime, (before+after)/2);
360 if (delta < 10) break;
362 attempt++;
364 client->disconnect ();
365 nlinfo ("Universal time is %" NL_I64 "dms with a mean error of %" NL_I64 "dms", _CUniTime::getUniTime(), bestdelta/2);
366 return;
367 error:
368 nlwarning ("there's no connection or lost or can't synchronize universal time");
369 ***************************************************************/
374 // Commands
377 NLMISC_CATEGORISED_COMMAND(nel, time, "displays the universal time", "")
379 if(args.size() != 0) return false;
381 if ( _CUniTime::Sync )
383 log.displayNL ("CTime::getLocalTime(): %" NL_I64 "dms, _CUniTime::getUniTime(): %" NL_I64 "dms", CTime::getLocalTime (), _CUniTime::getUniTime ());
384 log.displayNL ("_CUniTime::getStringUniTime(): '%s'", _CUniTime::getStringUniTime());
386 else
388 log.displayNL ("CTime::getLocalTime(): %" NL_I64 "dms <Universal time not sync>", CTime::getLocalTime ());
391 return true;
395 } // NLNET