1 // SoftEther VPN Source Code - Stable Edition Repository
2 // Mayaqua Kernel
3 //
4 // SoftEther VPN Server, Client and Bridge are free software under the Apache License, Version 2.0.
5 //
6 // Copyright (c) Daiyuu Nobori.
7 // Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan.
8 // Copyright (c) SoftEther Corporation.
9 // Copyright (c) all contributors on SoftEther VPN project in GitHub.
10 //
11 // All Rights Reserved.
12 //
13 // http://www.softether.org/
14 //
15 // This stable branch is officially managed by Daiyuu Nobori, the owner of SoftEther VPN Project.
16 // Pull requests should be sent to the Developer Edition Master Repository on https://github.com/SoftEtherVPN/SoftEtherVPN
17 // Contributors:
18 // - nattoheaven (https://github.com/nattoheaven)
19 //
20 // License: The Apache License, Version 2.0
21 // https://www.apache.org/licenses/LICENSE-2.0
22 //
23 // DISCLAIMER
24 // ==========
25 //
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 // SOFTWARE.
33 //
34 // THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN, UNDER
35 // JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY, MERGE, PUBLISH,
36 // DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS SOFTWARE, THAT ANY
37 // JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS SOFTWARE OR ITS CONTENTS,
38 // AGAINST US (SOFTETHER PROJECT, SOFTETHER CORPORATION, DAIYUU NOBORI OR OTHER
39 // SUPPLIERS), OR ANY JURIDICAL DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND
40 // OF USING, COPYING, MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING,
41 // AND/OR SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
42 // CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO EXCLUSIVE
43 // JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO, JAPAN. YOU MUST WAIVE
44 // ALL DEFENSES OF LACK OF PERSONAL JURISDICTION AND FORUM NON CONVENIENS.
45 // PROCESS MAY BE SERVED ON EITHER PARTY IN THE MANNER AUTHORIZED BY APPLICABLE
46 // LAW OR COURT RULE.
47 //
48 // USE ONLY IN JAPAN. DO NOT USE THIS SOFTWARE IN ANOTHER COUNTRY UNLESS YOU HAVE
49 // A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY CRIMINAL LAWS OR CIVIL
50 // RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS SOFTWARE IN OTHER COUNTRIES IS
51 // COMPLETELY AT YOUR OWN RISK. THE SOFTETHER VPN PROJECT HAS DEVELOPED AND
52 // DISTRIBUTED THIS SOFTWARE TO COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING
53 // CIVIL RIGHTS INCLUDING PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER
54 // COUNTRIES' LAWS OR CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES.
55 // WE HAVE NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR
56 // INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+ COUNTRIES
57 // AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE WORLD, WITH
58 // DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY COUNTRIES' LAWS, REGULATIONS
59 // AND CIVIL RIGHTS TO MAKE THE SOFTWARE COMPLY WITH ALL COUNTRIES' LAWS BY THE
60 // PROJECT. EVEN IF YOU WILL BE SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A
61 // PUBLIC SERVANT IN YOUR COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE
62 // LIABLE TO RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL
63 // RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT JUST A
64 // STATEMENT FOR WARNING AND DISCLAIMER.
65 //
66 // READ AND UNDERSTAND THE 'WARNING.TXT' FILE BEFORE USING THIS SOFTWARE.
67 // SOME SOFTWARE PROGRAMS FROM THIRD PARTIES ARE INCLUDED ON THIS SOFTWARE WITH
68 // LICENSE CONDITIONS WHICH ARE DESCRIBED ON THE 'THIRD_PARTY.TXT' FILE.
69 //
70 //
71 // SOURCE CODE CONTRIBUTION
72 // ------------------------
73 //
74 // Your contribution to SoftEther VPN Project is much appreciated.
75 // Please send patches to us through GitHub.
76 // Read the SoftEther VPN Patch Acceptance Policy in advance:
77 // http://www.softether.org/5-download/src/9.patch
78 //
79 //
80 // DEAR SECURITY EXPERTS
81 // ---------------------
82 //
83 // If you find a bug or a security vulnerability please kindly inform us
84 // about the problem immediately so that we can fix the security problem
85 // to protect a lot of users around the world as soon as possible.
86 //
87 // Our e-mail address for security reports is:
88 // softether-vpn-security [at] softether.org
89 //
90 // Please note that the above e-mail address is not a technical support
91 // inquiry address. If you need technical assistance, please visit
92 // http://www.softether.org/ and ask your question on the users forum.
93 //
94 // Thank you for your cooperation.
95 //
96 //
97 // NO MEMORY OR RESOURCE LEAKS
98 // ---------------------------
99 //
100 // The memory-leaks and resource-leaks verification under the stress
101 // test has been passed before release this source code.
102
103
104 // Kernel.c
105 // System service processing routine
106
107 #include <GlobalConst.h>
108
109 #include <stdio.h>
110 #include <stdlib.h>
111 #include <string.h>
112 #include <wchar.h>
113 #include <stdarg.h>
114 #include <time.h>
115 #include <errno.h>
116 #include <Mayaqua/Mayaqua.h>
117
118 #ifndef TM_YEAR_MAX
119 #define TM_YEAR_MAX 2106
120 #endif
121 #ifndef TM_MON_MAX
122 #define TM_MON_MAX 1
123 #endif
124 #ifndef TM_MDAY_MAX
125 #define TM_MDAY_MAX 7
126 #endif
127 #ifndef TM_HOUR_MAX
128 #define TM_HOUR_MAX 6
129 #endif
130 #ifndef TM_MIN_MAX
131 #define TM_MIN_MAX 28
132 #endif
133 #ifndef TM_SEC_MAX
134 #define TM_SEC_MAX 14
135 #endif
136
137 #define ADJUST_TM(tm_member, tm_carry, modulus) \
138 if ((tm_member) < 0){ \
139 tm_carry -= (1 - ((tm_member)+1) / (modulus)); \
140 tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \
141 } else if ((tm_member) >= (modulus)) { \
142 tm_carry += (tm_member) / (modulus); \
143 tm_member = (tm_member) % (modulus); \
144 }
145 #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
146 #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
147 #define leapday(m, y) ((m) == 1 && leap (y))
148 #define monthlen(m, y) (ydays[(m)+1] - ydays[m] + leapday (m, y))
149 static int ydays[] =
150 {
151 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
152 };
153
154 static UINT current_num_thread = 0;
155 static UINT cached_number_of_cpus = 0;
156
157
158
159 static wchar_t *default_locale_str =
160 L"- - $ : : $ Sun Mon Tue Wed Thu Fri Sat : : : $ (None)";
161
162
163 static LOCALE current_locale;
164 LOCK *tick_manual_lock = NULL;
165 UINT g_zero = 0;
166
167 #define MONSPERYEAR 12
168 #define DAYSPERNYEAR 365
169 #define DAYSPERLYEAR 366
170 #define SECSPERMIN 60
171 #define SECSPERHOUR (60*60)
172 #define SECSPERDAY (24*60*60)
173 #define DAYSPERWEEK 7
174 #define TM_SUNDAY 0
175 #define TM_MONDAY 1
176 #define TM_TUESDAY 2
177 #define TM_WEDNESDAY 3
178 #define TM_THURSDAY 4
179 #define TM_FRIDAY 5
180 #define TM_SATURDAY 6
181
182 #define TM_YEAR_BASE 1900
183
184 #define EPOCH_YEAR 1970
185 #define EPOCH_WDAY TM_THURSDAY
186
187 #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
188
189 static const int mon_lengths[2][MONSPERYEAR] = {
190 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
191 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
192 };
193
194 static const int year_lengths[2] = {
195 DAYSPERNYEAR, DAYSPERLYEAR
196 };
197
198
199 /*
200 * Taken from FreeBSD src / lib / libc / stdtime / localtime.c 1.43 revision.
201 * localtime.c 7.78.
202 * tzfile.h 1.8
203 * adapted to be replacement gmtime_r.
204 */
205 static void
c_timesub(timep,offset,tmp)206 c_timesub(timep, offset, tmp)
207 const time_64t * const timep;
208 const long offset;
209 struct tm * const tmp;
210 {
211 INT64 days;
212 INT64 rem;
213 INT64 y;
214 int yleap;
215 const int * ip;
216
217 days = *timep / SECSPERDAY;
218 rem = *timep % SECSPERDAY;
219 rem += (offset);
220 while (rem < 0) {
221 rem += SECSPERDAY;
222 --days;
223 }
224 while (rem >= SECSPERDAY) {
225 rem -= SECSPERDAY;
226 ++days;
227 }
228 tmp->tm_hour = (int) (rem / SECSPERHOUR);
229 rem = rem % SECSPERHOUR;
230 tmp->tm_min = (int) (rem / SECSPERMIN);
231 /*
232 ** A positive leap second requires a special
233 ** representation. This uses "... ??:59:60" et seq.
234 */
235 tmp->tm_sec = (int) (rem % SECSPERMIN) ;
236 tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
237 if (tmp->tm_wday < 0)
238 tmp->tm_wday += DAYSPERWEEK;
239 y = EPOCH_YEAR;
240 #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
241 while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
242 INT64 newy;
243
244 newy = y + days / DAYSPERNYEAR;
245 if (days < 0)
246 --newy;
247 days -= (newy - y) * DAYSPERNYEAR +
248 LEAPS_THRU_END_OF(newy - 1) -
249 LEAPS_THRU_END_OF(y - 1);
250 y = newy;
251 }
252 tmp->tm_year = (int)(y - TM_YEAR_BASE);
253 tmp->tm_yday = (int) days;
254 ip = mon_lengths[yleap];
255 for (tmp->tm_mon = 0; days >= (INT64) ip[tmp->tm_mon]; ++(tmp->tm_mon))
256 days = days - (INT64) ip[tmp->tm_mon];
257 tmp->tm_mday = (int) (days + 1);
258 tmp->tm_isdst = 0;
259 }
260
261 /*
262 * Re-entrant version of gmtime.
263 */
c_gmtime_r(const time_64t * timep,struct tm * tm)264 struct tm * c_gmtime_r(const time_64t* timep, struct tm *tm)
265 {
266 c_timesub(timep, 0L, tm);
267 return tm;
268 }
269
270 // Get the real-time system timer
TickRealtime()271 UINT TickRealtime()
272 {
273 #if defined(OS_WIN32) || defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) || defined(CLOCK_HIGHRES) || defined(UNIX_MACOS)
274 return Tick() + 1;
275 #else
276 return TickRealtimeManual() + 1;
277 #endif
278 }
279
280 #ifndef OS_WIN32
281
282 static UINT64 last_manual_tick = 0;
283 static UINT64 manual_tick_add_value = 0;
284
285 // For systems which not have clock_gettime (such as MacOS X)
TickRealtimeManual()286 UINT TickRealtimeManual()
287 {
288 UINT64 ret;
289 Lock(tick_manual_lock);
290 {
291 ret = TickGetRealtimeTickValue64();
292
293 if (last_manual_tick != 0 && (last_manual_tick > ret))
294 {
295 manual_tick_add_value += (last_manual_tick - ret);
296 }
297
298 last_manual_tick = ret;
299 }
300 Unlock(tick_manual_lock);
301
302 return (UINT)(ret + manual_tick_add_value);
303 }
304
305 // Returns a appropriate value from the current time
TickGetRealtimeTickValue64()306 UINT64 TickGetRealtimeTickValue64()
307 {
308 struct timeval tv;
309 struct timezone tz;
310 UINT64 ret;
311
312 memset(&tv, 0, sizeof(tv));
313 memset(&tz, 0, sizeof(tz));
314
315 gettimeofday(&tv, &tz);
316
317 if (sizeof(tv.tv_sec) != 4)
318 {
319 ret = (UINT64)tv.tv_sec * 1000ULL + (UINT64)tv.tv_usec / 1000ULL;
320 }
321 else
322 {
323 ret = (UINT64)((UINT64)((UINT32)tv.tv_sec)) * 1000ULL + (UINT64)tv.tv_usec / 1000ULL;
324 }
325
326 return ret;
327 }
328
329 #endif // OS_WIN32
330
331 // Get the number of CPUs
GetNumberOfCpu()332 UINT GetNumberOfCpu()
333 {
334 UINT ret = 0;
335
336 if (cached_number_of_cpus == 0)
337 {
338 UINT i = 0;
339
340 #ifdef OS_WIN32
341 i = Win32GetNumberOfCpuInner();
342 #else // OS_WIN32
343 i = UnixGetNumberOfCpuInner();
344 #endif // OS_WIN32
345
346 if (i == 0)
347 {
348 i = 8;
349 }
350
351 cached_number_of_cpus = i;
352 }
353
354 ret = cached_number_of_cpus;
355
356 if (ret == 0)
357 {
358 ret = 1;
359 }
360 if (ret > 128)
361 {
362 ret = 128;
363 }
364
365 return ret;
366 }
367
368 // Creating a thread list
NewThreadList()369 LIST *NewThreadList()
370 {
371 LIST *o = NewList(NULL);
372
373 return o;
374 }
375
376 // Remove the thread from the thread list
DelThreadFromThreadList(LIST * o,THREAD * t)377 void DelThreadFromThreadList(LIST *o, THREAD *t)
378 {
379 // Validate arguments
380 if (o == NULL || t == NULL)
381 {
382 return;
383 }
384
385 LockList(o);
386 {
387 if (Delete(o, t))
388 {
389 ReleaseThread(t);
390 }
391 }
392 UnlockList(o);
393 }
394
395 // Add the thread to the thread list
AddThreadToThreadList(LIST * o,THREAD * t)396 void AddThreadToThreadList(LIST *o, THREAD *t)
397 {
398 // Validate arguments
399 if (o == NULL || t == NULL)
400 {
401 return;
402 }
403
404 LockList(o);
405 {
406 if (IsInList(o, t) == false)
407 {
408 AddRef(t->ref);
409
410 Add(o, t);
411 }
412 }
413 UnlockList(o);
414 }
415
416 // Maintain thread list
MainteThreadList(LIST * o)417 void MainteThreadList(LIST *o)
418 {
419 UINT i;
420 LIST *delete_list = NULL;
421 // Validate arguments
422 if (o == NULL)
423 {
424 return;
425 }
426
427 LockList(o);
428 {
429 for (i = 0;i < LIST_NUM(o);i++)
430 {
431 THREAD *t = LIST_DATA(o, i);
432
433 if (t->Stopped)
434 {
435 if (delete_list == NULL)
436 {
437 delete_list = NewListFast(NULL);
438 }
439
440 Add(delete_list, t);
441 }
442 }
443
444 if (delete_list != NULL)
445 {
446 for (i = 0;i < LIST_NUM(delete_list);i++)
447 {
448 THREAD *t = LIST_DATA(delete_list, i);
449
450 ReleaseThread(t);
451
452 Delete(o, t);
453 }
454
455 ReleaseList(delete_list);
456 }
457 }
458 UnlockList(o);
459 }
460
461 // Wait until all threads in the thread list will be stopped
WaitAllThreadsWillBeStopped(LIST * o)462 void WaitAllThreadsWillBeStopped(LIST *o)
463 {
464 // Validate arguments
465 if (o == NULL)
466 {
467 return;
468 }
469
470 while (LIST_NUM(o) != 0)
471 {
472 SleepThread(100);
473 }
474 }
475
476 // Stop all the threads in the thread list
StopThreadList(LIST * o)477 void StopThreadList(LIST *o)
478 {
479 UINT i;
480 // Validate arguments
481 if (o == NULL)
482 {
483 return;
484 }
485
486 LockList(o);
487 {
488 for (i = 0;i < LIST_NUM(o);i++)
489 {
490 THREAD *t = LIST_DATA(o, i);
491
492 WaitThread(t, INFINITE);
493 }
494 }
495 UnlockList(o);
496 }
497
498 // Release the thread list
FreeThreadList(LIST * o)499 void FreeThreadList(LIST *o)
500 {
501 UINT i;
502 // Validate arguments
503 if (o == NULL)
504 {
505 return;
506 }
507
508 LockList(o);
509 {
510 for (i = 0;i < LIST_NUM(o);i++)
511 {
512 THREAD *t = LIST_DATA(o, i);
513
514 WaitThread(t, INFINITE);
515
516 ReleaseThread(t);
517 }
518
519 DeleteAll(o);
520 }
521 UnlockList(o);
522
523 ReleaseList(o);
524 }
525
526 // Get the home directory
GetHomeDirW(wchar_t * path,UINT size)527 void GetHomeDirW(wchar_t *path, UINT size)
528 {
529 // Validate arguments
530 if (path == NULL)
531 {
532 return;
533 }
534
535 if (GetEnvW(L"HOME", path, size) == false)
536 {
537 wchar_t drive[MAX_SIZE];
538 wchar_t hpath[MAX_SIZE];
539 if (GetEnvW(L"HOMEDRIVE", drive, sizeof(drive)) &&
540 GetEnvW(L"HOMEPATH", hpath, sizeof(hpath)))
541 {
542 UniFormat(path, size, L"%s%s", drive, hpath);
543 }
544 else
545 {
546 #ifdef OS_WIN32
547 Win32GetCurrentDirW(path, size);
548 #else // OS_WIN32
549 UnixGetCurrentDirW(path, size);
550 #endif // OS_WIN32
551 }
552 }
553 }
GetHomeDir(char * path,UINT size)554 void GetHomeDir(char *path, UINT size)
555 {
556 // Validate arguments
557 if (path == NULL)
558 {
559 return;
560 }
561
562 if (GetEnv("HOME", path, size) == false)
563 {
564 char drive[MAX_SIZE];
565 char hpath[MAX_SIZE];
566 if (GetEnv("HOMEDRIVE", drive, sizeof(drive)) &&
567 GetEnv("HOMEPATH", hpath, sizeof(hpath)))
568 {
569 Format(path, size, "%s%s", drive, hpath);
570 }
571 else
572 {
573 #ifdef OS_WIN32
574 Win32GetCurrentDir(path, size);
575 #else // OS_WIN32
576 UnixGetCurrentDir(path, size);
577 #endif // OS_WIN32
578 }
579 }
580 }
581
582 // Get the environment variable string
GetEnv(char * name,char * data,UINT size)583 bool GetEnv(char *name, char *data, UINT size)
584 {
585 char *ret;
586 // Validate arguments
587 if (name == NULL || data == NULL)
588 {
589 return false;
590 }
591
592 StrCpy(data, size, "");
593
594 ret = getenv(name);
595 if (ret == NULL)
596 {
597 return false;
598 }
599
600 StrCpy(data, size, ret);
601
602 return true;
603 }
GetEnvW(wchar_t * name,wchar_t * data,UINT size)604 bool GetEnvW(wchar_t *name, wchar_t *data, UINT size)
605 {
606 #ifdef OS_WIN32
607 return GetEnvW_ForWin32(name, data, size);
608 #else // OS_WIN32
609 return GetEnvW_ForUnix(name, data, size);
610 #endif // OS_WIN32
611 }
612
613 #ifdef OS_WIN32
GetEnvW_ForWin32(wchar_t * name,wchar_t * data,UINT size)614 bool GetEnvW_ForWin32(wchar_t *name, wchar_t *data, UINT size)
615 {
616 wchar_t *ret;
617 // Validate arguments
618 if (name == NULL || data == NULL)
619 {
620 return false;
621 }
622
623 if (IsNt() == false)
624 {
625 bool ret;
626 char *name_a = CopyUniToStr(name);
627 char data_a[MAX_SIZE];
628
629 ret = GetEnv(name_a, data_a, sizeof(data_a));
630
631 if (ret)
632 {
633 StrToUni(data, size, data_a);
634 }
635
636 Free(name_a);
637
638 return ret;
639 }
640
641 UniStrCpy(data, size, L"");
642
643 ret = _wgetenv(name);
644 if (ret == NULL)
645 {
646 return false;
647 }
648
649 UniStrCpy(data, size, ret);
650
651 return true;
652 }
653
654 #endif // OS_WIN32
655
656 #ifdef OS_UNIX
657
GetEnvW_ForUnix(wchar_t * name,wchar_t * data,UINT size)658 bool GetEnvW_ForUnix(wchar_t *name, wchar_t *data, UINT size)
659 {
660 char *name_a;
661 bool ret;
662 char data_a[MAX_SIZE];
663 // Validate arguments
664 if (name == NULL || data == NULL)
665 {
666 return false;
667 }
668
669 name_a = CopyUniToUtf(name);
670
671 ret = GetEnv(name_a, data_a, sizeof(data_a));
672
673 if (ret)
674 {
675 UtfToUni(data, size, data_a);
676 }
677
678 Free(name_a);
679
680 return ret;
681 }
682
683 #endif // OS_UNIX
684
685 // Get the memory information
GetMemInfo(MEMINFO * info)686 void GetMemInfo(MEMINFO *info)
687 {
688 OSGetMemInfo(info);
689 }
690
691 // Start the single-instance
NewSingleInstance(char * instance_name)692 INSTANCE *NewSingleInstance(char *instance_name)
693 {
694 return NewSingleInstanceEx(instance_name, false);
695 }
NewSingleInstanceEx(char * instance_name,bool user_local)696 INSTANCE *NewSingleInstanceEx(char *instance_name, bool user_local)
697 {
698 char name[MAX_SIZE];
699 INSTANCE *ret;
700 void *data;
701
702 if (instance_name != NULL)
703 {
704 if (user_local == false)
705 {
706 HashInstanceName(name, sizeof(name), instance_name);
707 }
708 else
709 {
710 HashInstanceNameLocal(name, sizeof(name), instance_name);
711 }
712
713 data = OSNewSingleInstance(name);
714 }
715 else
716 {
717 data = OSNewSingleInstance(NULL);
718 }
719
720 if (data == NULL)
721 {
722 return NULL;
723 }
724
725 ret = ZeroMalloc(sizeof(INSTANCE));
726 if (instance_name != NULL)
727 {
728 ret->Name = CopyStr(instance_name);
729 }
730
731 ret->pData = data;
732
733 return ret;
734 }
735
736 // Release of single instance
FreeSingleInstance(INSTANCE * inst)737 void FreeSingleInstance(INSTANCE *inst)
738 {
739 // Validate arguments
740 if (inst == NULL)
741 {
742 return;
743 }
744
745 OSFreeSingleInstance(inst->pData);
746
747 if (inst->Name != NULL)
748 {
749 Free(inst->Name);
750 }
751 Free(inst);
752 }
753
754 // Hashing the instance name
HashInstanceName(char * name,UINT size,char * instance_name)755 void HashInstanceName(char *name, UINT size, char *instance_name)
756 {
757 char tmp[MAX_SIZE];
758 UCHAR hash[SHA1_SIZE];
759 char key[11];
760 // Validate arguments
761 if (name == NULL || instance_name == NULL)
762 {
763 return;
764 }
765
766 StrCpy(tmp, sizeof(tmp), instance_name);
767 Trim(tmp);
768 StrUpper(tmp);
769
770 Hash(hash, tmp, StrLen(tmp), SHA1_SIZE);
771 BinToStr(key, sizeof(key), hash, 5);
772 key[10] = 0;
773
774 Format(name, size, "VPN-%s", key);
775
776 if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType))
777 {
778 if (GET_KETA(GetOsInfo()->OsType, 100) >= 2 ||
779 GetOsInfo()->OsType == OSTYPE_WINDOWS_NT_4_TERMINAL_SERVER)
780 {
781 StrCpy(tmp, sizeof(tmp), name);
782 Format(name, size, "Global\\%s", tmp);
783 }
784 }
785 }
HashInstanceNameLocal(char * name,UINT size,char * instance_name)786 void HashInstanceNameLocal(char *name, UINT size, char *instance_name)
787 {
788 char tmp[MAX_SIZE];
789 UCHAR hash[SHA1_SIZE];
790 char key[11];
791 // Validate arguments
792 if (name == NULL || instance_name == NULL)
793 {
794 return;
795 }
796
797 StrCpy(tmp, sizeof(tmp), instance_name);
798 Trim(tmp);
799 StrUpper(tmp);
800
801 Hash(hash, tmp, StrLen(tmp), SHA1_SIZE);
802 BinToStr(key, sizeof(key), hash, 5);
803 key[10] = 0;
804
805 Format(name, size, "VPN-%s", key);
806
807 if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType))
808 {
809 if (GET_KETA(GetOsInfo()->OsType, 100) >= 2 ||
810 GetOsInfo()->OsType == OSTYPE_WINDOWS_NT_4_TERMINAL_SERVER)
811 {
812 StrCpy(tmp, sizeof(tmp), name);
813 Format(name, size, "Local\\%s", tmp);
814 }
815 }
816 }
817
818 // Run the process
Run(char * filename,char * arg,bool hide,bool wait)819 bool Run(char *filename, char *arg, bool hide, bool wait)
820 {
821 // Validate arguments
822 if (filename == NULL)
823 {
824 return false;
825 }
826
827 return OSRun(filename, arg, hide, wait);
828 }
RunW(wchar_t * filename,wchar_t * arg,bool hide,bool wait)829 bool RunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait)
830 {
831 // Validate arguments
832 if (filename == NULL)
833 {
834 return false;
835 }
836
837 return OSRunW(filename, arg, hide, wait);
838 }
839
840 // Date and time related functions
GetDateTimeStr64Uni(wchar_t * str,UINT size,UINT64 sec64)841 void GetDateTimeStr64Uni(wchar_t *str, UINT size, UINT64 sec64)
842 {
843 char tmp[MAX_SIZE];
844 if (str == NULL)
845 {
846 return;
847 }
848
849 GetDateTimeStr64(tmp, sizeof(tmp), sec64);
850 StrToUni(str, size, tmp);
851 }
GetDateTimeStr64(char * str,UINT size,UINT64 sec64)852 void GetDateTimeStr64(char *str, UINT size, UINT64 sec64)
853 {
854 SYSTEMTIME st;
855 UINT64ToSystem(&st, sec64);
856 GetDateTimeStr(str, size, &st);
857 }
GetDateTimeStrMilli64(char * str,UINT size,UINT64 sec64)858 void GetDateTimeStrMilli64(char *str, UINT size, UINT64 sec64)
859 {
860 SYSTEMTIME st;
861 UINT64ToSystem(&st, sec64);
862 GetDateTimeStrMilli(str, size, &st);
863 }
GetDateTimeStrMilli64ForFileName(char * str,UINT size,UINT64 sec64)864 void GetDateTimeStrMilli64ForFileName(char *str, UINT size, UINT64 sec64)
865 {
866 SYSTEMTIME st;
867 UINT64ToSystem(&st, sec64);
868 GetDateTimeStrMilliForFileName(str, size, &st);
869 }
GetDateTimeStrMilliForFileName(char * str,UINT size,SYSTEMTIME * tm)870 void GetDateTimeStrMilliForFileName(char *str, UINT size, SYSTEMTIME *tm)
871 {
872 Format(str, size, "%04u%02u%02u_%02u%02u%02u",
873 tm->wYear, tm->wMonth, tm->wDay, tm->wHour, tm->wMinute, tm->wSecond);
874 }
GetDateStr64(char * str,UINT size,UINT64 sec64)875 void GetDateStr64(char *str, UINT size, UINT64 sec64)
876 {
877 SYSTEMTIME st;
878 if (sec64 == 0)
879 {
880 StrCpy(str, size, "(Unknown)");
881 return;
882 }
883 UINT64ToSystem(&st, sec64);
884 GetDateStr(str, size, &st);
885 }
GetDateTimeStrEx64(wchar_t * str,UINT size,UINT64 sec64,LOCALE * locale)886 void GetDateTimeStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)
887 {
888 SYSTEMTIME st;
889 if (locale == NULL)
890 {
891 locale = ¤t_locale;
892 }
893 if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
894 {
895 UniStrCpy(str, size, locale->Unknown);
896 return;
897 }
898 UINT64ToSystem(&st, sec64);
899 GetDateTimeStrEx(str, size, &st, locale);
900 }
GetTimeStrEx64(wchar_t * str,UINT size,UINT64 sec64,LOCALE * locale)901 void GetTimeStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)
902 {
903 SYSTEMTIME st;
904 if (locale == NULL)
905 {
906 locale = ¤t_locale;
907 }
908 if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
909 {
910 UniStrCpy(str, size, locale->Unknown);
911 return;
912 }
913 UINT64ToSystem(&st, sec64);
914 GetTimeStrEx(str, size, &st, locale);
915 }
GetDateStrEx64(wchar_t * str,UINT size,UINT64 sec64,LOCALE * locale)916 void GetDateStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)
917 {
918 SYSTEMTIME st;
919 if (locale == NULL)
920 {
921 locale = ¤t_locale;
922 }
923 if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
924 {
925 UniStrCpy(str, size, locale->Unknown);
926 return;
927 }
928 UINT64ToSystem(&st, sec64);
929 GetDateStrEx(str, size, &st, locale);
930 }
GetTimeStrMilli64(char * str,UINT size,UINT64 sec64)931 void GetTimeStrMilli64(char *str, UINT size, UINT64 sec64)
932 {
933 SYSTEMTIME st;
934 if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
935 {
936 StrCpy(str, size, "(Unknown)");
937 return;
938 }
939 UINT64ToSystem(&st, sec64);
940 GetTimeStrMilli(str, size, &st);
941 }
GetTimeStr64(char * str,UINT size,UINT64 sec64)942 void GetTimeStr64(char *str, UINT size, UINT64 sec64)
943 {
944 SYSTEMTIME st;
945 if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
946 {
947 StrCpy(str, size, "(Unknown)");
948 return;
949 }
950 UINT64ToSystem(&st, sec64);
951 GetTimeStr(str, size, &st);
952 }
953
954 // Convert to a time to be used safely in the current POSIX implementation
SafeTime64(UINT64 sec64)955 UINT64 SafeTime64(UINT64 sec64)
956 {
957 return MAKESURE(sec64, 0, 4102243323123ULL);
958 }
959
960 // Thread pool
961 static SK *thread_pool = NULL;
962 static COUNTER *thread_count = NULL;
963
964 // Initialization of thread pool
InitThreading()965 void InitThreading()
966 {
967 thread_pool = NewSk();
968 thread_count = NewCounter();
969 }
970
971 // Release of thread pool
FreeThreading()972 void FreeThreading()
973 {
974 while (true)
975 {
976 if (Count(thread_count) == 0)
977 {
978 break;
979 }
980
981 SleepThread(25);
982 }
983
984 while (true)
985 {
986 THREAD_POOL_DATA *pd;
987 THREAD *t = Pop(thread_pool);
988
989 if (t == NULL)
990 {
991 break;
992 }
993
994 pd = (THREAD_POOL_DATA *)t->param;
995
996 pd->ThreadProc = NULL;
997 Set(pd->Event);
998
999 WaitThreadInternal(t);
1000
1001 pd = (THREAD_POOL_DATA *)t->param;
1002 ReleaseEvent(pd->Event);
1003 ReleaseEvent(pd->InitFinishEvent);
1004
1005 ReleaseThreadInternal(t);
1006
1007 Free(pd);
1008 }
1009
1010 ReleaseSk(thread_pool);
1011
1012 DeleteCounter(thread_count);
1013 thread_count = NULL;
1014 }
1015
1016 // Thread pool procedure
ThreadPoolProc(THREAD * t,void * param)1017 void ThreadPoolProc(THREAD *t, void *param)
1018 {
1019 THREAD_POOL_DATA *pd;
1020 // Validate arguments
1021 if (t == NULL)
1022 {
1023 return;
1024 }
1025
1026 pd = (THREAD_POOL_DATA *)param;
1027
1028 NoticeThreadInitInternal(t);
1029
1030 while (true)
1031 {
1032 THREAD *thread;
1033 UINT i, num;
1034 EVENT **ee;
1035
1036 // Wait for the next job
1037 Wait(pd->Event, INFINITE);
1038
1039 if (pd->ThreadProc == NULL)
1040 {
1041 // Stop the pool thread
1042 break;
1043 }
1044
1045 thread = pd->Thread;
1046 thread->ThreadId = ThreadId();
1047
1048 // Initialization is completed
1049 Set(pd->InitFinishEvent);
1050
1051 // Set the thread name
1052 if (thread->Name != NULL)
1053 {
1054 SetThreadName(thread->ThreadId, thread->Name, thread->param);
1055 }
1056 else
1057 {
1058 SetThreadName(thread->ThreadId, "Unknown", 0);
1059 }
1060
1061 // Run the thread procedure
1062 pd->ThreadProc(pd->Thread, thread->param);
1063
1064 // Set the thread name
1065 SetThreadName(thread->ThreadId, NULL, 0);
1066
1067 pd->Thread->Stopped = true;
1068
1069 thread->PoolHalting = true;
1070
1071 // Set the waiting event list
1072 LockList(thread->PoolWaitList);
1073 {
1074 num = LIST_NUM(thread->PoolWaitList);
1075 ee = ToArray(thread->PoolWaitList);
1076
1077 DeleteAll(thread->PoolWaitList);
1078 }
1079 UnlockList(thread->PoolWaitList);
1080
1081 for (i = 0;i < num;i++)
1082 {
1083 EVENT *e = ee[i];
1084
1085 Set(e);
1086 ReleaseEvent(e);
1087 }
1088
1089 Free(ee);
1090
1091 while (true)
1092 {
1093 if (Count(thread->ref->c) <= 1)
1094 {
1095 break;
1096 }
1097
1098 Wait(thread->release_event, 256);
1099 }
1100
1101 ReleaseThread(thread);
1102
1103 #ifdef OS_WIN32
1104 // For Win32: Recover the priority of the thread
1105 MsRestoreThreadPriority();
1106 #endif // OS_WIN32
1107
1108 // Register the thread itself to the thread pool
1109 LockSk(thread_pool);
1110 {
1111 Push(thread_pool, t);
1112 }
1113 UnlockSk(thread_pool);
1114
1115 Dec(thread_count);
1116 }
1117 }
1118
1119 // Set the thread name
SetThreadName(uintmax_t thread_id,char * name,void * param)1120 void SetThreadName(uintmax_t thread_id, char *name, void *param)
1121 {
1122 #ifdef OS_WIN32
1123 if (IsDebug())
1124 {
1125 char tmp[MAX_SIZE];
1126
1127 if (name == NULL)
1128 {
1129 strcpy(tmp, "idle");
1130 }
1131 else
1132 {
1133 sprintf(tmp, "%s (0x%x)", name, (UINT)param);
1134 }
1135
1136 Win32SetThreadName(thread_id, tmp);
1137 }
1138 #else // OS_WIN32
1139 #ifdef _DEBUG
1140 #ifdef PR_SET_NAME
1141 char tmp[MAX_SIZE];
1142
1143 if (name == NULL)
1144 {
1145 strcpy(tmp, "idle");
1146 }
1147 else
1148 {
1149 sprintf(tmp, "%s (%p)", name, param);
1150 }
1151
1152 tmp[15] = 0;
1153
1154 prctl(PR_SET_NAME, (unsigned long)tmp, 0, 0, 0);
1155 #endif // PR_SET_NAME
1156 #endif // _DEBUG
1157 #endif // OS_WIN32
1158 }
1159
1160 // Do Nothing
DoNothing()1161 UINT DoNothing()
1162 {
1163 return g_zero;
1164 }
1165
1166 // Thread creation (pool)
NewThreadNamed(THREAD_PROC * thread_proc,void * param,char * name)1167 THREAD *NewThreadNamed(THREAD_PROC *thread_proc, void *param, char *name)
1168 {
1169 THREAD *host = NULL;
1170 THREAD_POOL_DATA *pd = NULL;
1171 THREAD *ret;
1172 bool new_thread = false;
1173 // Validate arguments
1174 if (thread_proc == NULL)
1175 {
1176 return NULL;
1177 }
1178
1179 if (IsTrackingEnabled() == false)
1180 {
1181 DoNothing();
1182 }
1183
1184 Inc(thread_count);
1185
1186 LockSk(thread_pool);
1187 {
1188 // Examine whether there is a thread that is currently vacant in the pool
1189 host = Pop(thread_pool);
1190 }
1191 UnlockSk(thread_pool);
1192
1193 if (host == NULL)
1194 {
1195 // Create a new thread because a vacant thread is not found
1196 pd = ZeroMalloc(sizeof(THREAD_POOL_DATA));
1197 pd->Event = NewEvent();
1198 pd->InitFinishEvent = NewEvent();
1199 host = NewThreadInternal(ThreadPoolProc, pd);
1200 WaitThreadInitInternal(host);
1201
1202 new_thread = true;
1203 }
1204 else
1205 {
1206 pd = (THREAD_POOL_DATA *)host->param;
1207 }
1208
1209 // Creating a thread pool
1210 ret = ZeroMalloc(sizeof(THREAD));
1211 ret->ref = NewRef();
1212 ret->thread_proc = thread_proc;
1213 ret->param = param;
1214 ret->pData = NULL;
1215 ret->init_finished_event = NewEvent();
1216 ret->PoolThread = true;
1217 ret->PoolWaitList = NewList(NULL);
1218 ret->PoolHostThread = host;
1219 ret->release_event = NewEvent();
1220
1221 if (IsEmptyStr(name) == false)
1222 {
1223 ret->Name = CopyStr(name);
1224 }
1225
1226 // Run
1227 pd->ThreadProc = thread_proc;
1228 pd->Thread = ret;
1229 AddRef(ret->ref);
1230
1231 Set(pd->Event);
1232
1233 Wait(pd->InitFinishEvent, INFINITE);
1234
1235 current_num_thread++;
1236
1237 // Debug("current_num_thread = %u\n", current_num_thread);
1238
1239 return ret;
1240 }
1241
1242 // Clean up of thread (pool)
CleanupThread(THREAD * t)1243 void CleanupThread(THREAD *t)
1244 {
1245 // Validate arguments
1246 if (t == NULL)
1247 {
1248 return;
1249 }
1250
1251 ReleaseEvent(t->init_finished_event);
1252 ReleaseEvent(t->release_event);
1253 ReleaseList(t->PoolWaitList);
1254
1255 if (t->Name != NULL)
1256 {
1257 Free(t->Name);
1258 }
1259
1260 Free(t);
1261
1262 current_num_thread--;
1263 //Debug("current_num_thread = %u\n", current_num_thread);
1264 }
1265
1266 // Release thread (pool)
ReleaseThread(THREAD * t)1267 void ReleaseThread(THREAD *t)
1268 {
1269 UINT ret;
1270 EVENT *e;
1271 // Validate arguments
1272 if (t == NULL)
1273 {
1274 return;
1275 }
1276
1277 e = t->release_event;
1278 if (e != NULL)
1279 {
1280 AddRef(e->ref);
1281 }
1282
1283 ret = Release(t->ref);
1284 Set(e);
1285
1286 ReleaseEvent(e);
1287
1288 if (ret == 0)
1289 {
1290 CleanupThread(t);
1291 }
1292 }
1293
1294 // Notify the completion of the thread initialization (pool)
NoticeThreadInit(THREAD * t)1295 void NoticeThreadInit(THREAD *t)
1296 {
1297 // Validate arguments
1298 if (t == NULL)
1299 {
1300 return;
1301 }
1302
1303 // Notification
1304 Set(t->init_finished_event);
1305 }
1306
1307 // Wait the completion of the thread initialization (pool)
WaitThreadInit(THREAD * t)1308 void WaitThreadInit(THREAD *t)
1309 {
1310 // Validate arguments
1311 if (t == NULL)
1312 {
1313 return;
1314 }
1315
1316 // KS
1317 KS_INC(KS_WAITFORTHREAD_COUNT);
1318
1319 // Wait
1320 Wait(t->init_finished_event, INFINITE);
1321 }
1322
1323 // Wait for the termination of the thread (pool)
WaitThread(THREAD * t,UINT timeout)1324 bool WaitThread(THREAD *t, UINT timeout)
1325 {
1326 bool ret = false;
1327 EVENT *e = NULL;
1328 // Validate arguments
1329 if (t == NULL)
1330 {
1331 return false;
1332 }
1333
1334 LockList(t->PoolWaitList);
1335 {
1336 if (t->PoolHalting)
1337 {
1338 // Has already been stopped
1339 ret = true;
1340 }
1341 else
1342 {
1343 // Register the completion notifying event to the list
1344 e = NewEvent();
1345 AddRef(e->ref);
1346 Insert(t->PoolWaitList, e);
1347 }
1348 }
1349 UnlockList(t->PoolWaitList);
1350
1351 if (e != NULL)
1352 {
1353 // Wait Event
1354 ret = Wait(e, timeout);
1355
1356 LockList(t->PoolWaitList);
1357 {
1358 if (Delete(t->PoolWaitList, e))
1359 {
1360 ReleaseEvent(e);
1361 }
1362 }
1363 UnlockList(t->PoolWaitList);
1364
1365 ReleaseEvent(e);
1366 }
1367
1368 return ret;
1369 }
1370
1371 // Get Thread ID
ThreadId()1372 UINT ThreadId()
1373 {
1374 return OSThreadId();
1375 }
1376
1377 // Creating a thread
NewThreadInternal(THREAD_PROC * thread_proc,void * param)1378 THREAD *NewThreadInternal(THREAD_PROC *thread_proc, void *param)
1379 {
1380 THREAD *t;
1381 UINT retry = 0;
1382 // Validate arguments
1383 if (thread_proc == NULL)
1384 {
1385 return NULL;
1386 }
1387
1388 // Initialize Thread object
1389 t = ZeroMalloc(sizeof(THREAD));
1390 t->init_finished_event = NewEvent();
1391
1392 t->param = param;
1393 t->ref = NewRef();
1394 t->thread_proc = thread_proc;
1395
1396 // Wait until the OS to initialize the thread
1397 while (true)
1398 {
1399 if ((retry++) > 60)
1400 {
1401 printf("\n\n*** error: new thread create failed.\n\n");
1402 AbortExit();
1403 }
1404 if (OSInitThread(t))
1405 {
1406 break;
1407 }
1408 SleepThread(500);
1409 }
1410
1411 // KS
1412 KS_INC(KS_NEWTHREAD_COUNT);
1413
1414 return t;
1415 }
1416
1417 // Release of thread
ReleaseThreadInternal(THREAD * t)1418 void ReleaseThreadInternal(THREAD *t)
1419 {
1420 // Validate arguments
1421 if (t == NULL)
1422 {
1423 return;
1424 }
1425
1426 if (Release(t->ref) == 0)
1427 {
1428 CleanupThreadInternal(t);
1429 }
1430 }
1431
1432 // Clean up of the thread
CleanupThreadInternal(THREAD * t)1433 void CleanupThreadInternal(THREAD *t)
1434 {
1435 // Validate arguments
1436 if (t == NULL)
1437 {
1438 return;
1439 }
1440
1441 // Release of the thread
1442 OSFreeThread(t);
1443
1444 // Release the event
1445 ReleaseEvent(t->init_finished_event);
1446 // Memory release
1447 Free(t);
1448
1449 // KS
1450 KS_INC(KS_FREETHREAD_COUNT);
1451 }
1452
1453 // Wait for the termination of the thread
WaitThreadInternal(THREAD * t)1454 bool WaitThreadInternal(THREAD *t)
1455 {
1456 // Validate arguments
1457 if (t == NULL)
1458 {
1459 return false;
1460 }
1461
1462 return OSWaitThread(t);
1463 }
1464
1465 // Notify that the thread initialization is complete
NoticeThreadInitInternal(THREAD * t)1466 void NoticeThreadInitInternal(THREAD *t)
1467 {
1468 // Validate arguments
1469 if (t == NULL)
1470 {
1471 return;
1472 }
1473
1474 // Notify
1475 Set(t->init_finished_event);
1476 }
1477
1478 // Wait for completion of thread initialization
WaitThreadInitInternal(THREAD * t)1479 void WaitThreadInitInternal(THREAD *t)
1480 {
1481 // Validate arguments
1482 if (t == NULL)
1483 {
1484 return;
1485 }
1486
1487 // KS
1488 KS_INC(KS_WAITFORTHREAD_COUNT);
1489
1490 // Wait
1491 Wait(t->init_finished_event, INFINITE);
1492 }
1493
1494 // Get the date and time string by using the locale information
GetDateTimeStrEx(wchar_t * str,UINT size,SYSTEMTIME * st,LOCALE * locale)1495 void GetDateTimeStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)
1496 {
1497 wchar_t tmp1[MAX_SIZE];
1498 wchar_t tmp2[MAX_SIZE];
1499 // Validate arguments
1500 if (str == NULL || st == NULL)
1501 {
1502 return;
1503 }
1504
1505 GetDateStrEx(tmp1, sizeof(tmp1), st, locale);
1506 GetTimeStrEx(tmp2, sizeof(tmp2), st, locale);
1507 UniFormat(str, size, L"%s %s", tmp1, tmp2);
1508 }
1509
1510 // Get the time string by using the locale information
GetTimeStrEx(wchar_t * str,UINT size,SYSTEMTIME * st,LOCALE * locale)1511 void GetTimeStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)
1512 {
1513 wchar_t *tag = L"%02u%s%02u%s%02u%s";
1514 // Validate arguments
1515 if (str == NULL || st == NULL)
1516 {
1517 return;
1518 }
1519
1520 if (_GETLANG() == SE_LANG_JAPANESE || _GETLANG() == SE_LANG_CHINESE_ZH)
1521 {
1522 tag = L"%2u%s%2u%s%2u%s";
1523 }
1524
1525 locale = (locale != NULL ? locale : ¤t_locale);
1526 UniFormat(str, size,
1527 tag,
1528 st->wHour, locale->HourStr,
1529 st->wMinute, locale->MinuteStr,
1530 st->wSecond, locale->SecondStr);
1531 }
1532
1533 // Get a date string by using the locale information
GetDateStrEx(wchar_t * str,UINT size,SYSTEMTIME * st,LOCALE * locale)1534 void GetDateStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)
1535 {
1536 wchar_t *tag = L"%04u%s%02u%s%02u%s (%s)";
1537 // Validate arguments
1538 if (str == NULL || st == NULL)
1539 {
1540 return;
1541 }
1542
1543 if (_GETLANG() == SE_LANG_JAPANESE || _GETLANG() == SE_LANG_CHINESE_ZH)
1544 {
1545 tag = L"%4u%s%2u%s%2u%s(%s)";
1546 }
1547
1548 locale = (locale != NULL ? locale : ¤t_locale);
1549 UniFormat(str, size,
1550 tag,
1551 st->wYear, locale->YearStr,
1552 st->wMonth, locale->MonthStr,
1553 st->wDay, locale->DayStr,
1554 locale->DayOfWeek[st->wDayOfWeek]);
1555 }
1556
1557 // Get the time string to milliseconds (for example, 12:34:56.789)
GetTimeStrMilli(char * str,UINT size,SYSTEMTIME * st)1558 void GetTimeStrMilli(char *str, UINT size, SYSTEMTIME *st)
1559 {
1560 // Validate arguments
1561 if (st == NULL || str == NULL)
1562 {
1563 return;
1564 }
1565
1566 Format(str, size, "%02u:%02u:%02u.%03u",
1567 st->wHour, st->wMinute, st->wSecond, st->wMilliseconds);
1568 }
1569
1570 // Get the time string (for example, 12:34:56)
GetTimeStr(char * str,UINT size,SYSTEMTIME * st)1571 void GetTimeStr(char *str, UINT size, SYSTEMTIME *st)
1572 {
1573 // Validate arguments
1574 if (str == NULL || st == NULL)
1575 {
1576 return;
1577 }
1578
1579 Format(str, size, "%02u:%02u:%02u",
1580 st->wHour, st->wMinute, st->wSecond);
1581 }
1582
1583 // Get the date string (example: 2004/07/23)
GetDateStr(char * str,UINT size,SYSTEMTIME * st)1584 void GetDateStr(char *str, UINT size, SYSTEMTIME *st)
1585 {
1586 // Validate arguments
1587 if (str == NULL || st == NULL)
1588 {
1589 return;
1590 }
1591
1592 Format(str, size, "%04u-%02u-%02u",
1593 st->wYear, st->wMonth, st->wDay);
1594 }
1595
1596 // Get the date and time string (example: 2004/07/23 12:34:56)
GetDateTimeStr(char * str,UINT size,SYSTEMTIME * st)1597 void GetDateTimeStr(char *str, UINT size, SYSTEMTIME *st)
1598 {
1599 // Validate arguments
1600 if (str == NULL || st == NULL)
1601 {
1602 return;
1603 }
1604
1605 Format(str, size, "%04u-%02u-%02u %02u:%02u:%02u",
1606 st->wYear, st->wMonth, st->wDay,
1607 st->wHour, st->wMinute, st->wSecond);
1608 }
1609
1610 // Get the date and time string in milliseconds (example: 2004/07/23 12:34:56.789)
GetDateTimeStrMilli(char * str,UINT size,SYSTEMTIME * st)1611 void GetDateTimeStrMilli(char *str, UINT size, SYSTEMTIME *st)
1612 {
1613 // Validate arguments
1614 if (str == NULL || st == NULL)
1615 {
1616 return;
1617 }
1618
1619 Format(str, size, "%04u-%02u-%02u %02u:%02u:%02u.%03u",
1620 st->wYear, st->wMonth, st->wDay,
1621 st->wHour, st->wMinute, st->wSecond,
1622 st->wMilliseconds);
1623 }
1624
1625 // Convert string RFC3339 format (example: 2017-09-27T18:25:55.434-9:00) to UINT64
DateTimeStrRFC3339ToSystemTime64(char * str)1626 UINT64 DateTimeStrRFC3339ToSystemTime64(char *str)
1627 {
1628 SYSTEMTIME st;
1629 if (DateTimeStrRFC3339ToSystemTime(&st, str))
1630 {
1631 return SystemToUINT64(&st);
1632 }
1633 else
1634 {
1635 return 0;
1636 }
1637 }
1638
1639 // Convert string RFC3339 format (example: 2017-09-27T18:25:55.434-9:00) to SYSTEMTIME
DateTimeStrRFC3339ToSystemTime(SYSTEMTIME * st,char * str)1640 bool DateTimeStrRFC3339ToSystemTime(SYSTEMTIME *st, char *str)
1641 {
1642 bool ok = false;
1643 UINT index_plus;
1644 char tmp[MAX_PATH];
1645 Zero(st, sizeof(SYSTEMTIME));
1646 if (st == NULL || str == NULL)
1647 {
1648 return false;
1649 }
1650
1651 StrCpy(tmp, sizeof(tmp), str);
1652
1653 index_plus = SearchStrEx(tmp, "+", 0, false);
1654 if (index_plus != INFINITE)
1655 {
1656 tmp[index_plus] = 0;
1657 }
1658
1659 if (StrLen(tmp) >= 19)
1660 {
1661 if (tmp[4] == '-' && tmp[7] == '-' && tmp[10] == 'T' && tmp[13] == ':' &&
1662 tmp[16] == ':')
1663 {
1664 char str_year[16], str_month[16], str_day[16], str_hour[16], str_minute[16],
1665 str_second[16], str_msec[16];
1666
1667 StrCpy(str_year, sizeof(str_year), tmp + 0);
1668 str_year[4] = 0;
1669
1670 StrCpy(str_month, sizeof(str_month), tmp + 5);
1671 str_month[2] = 0;
1672
1673 StrCpy(str_day, sizeof(str_day), tmp + 8);
1674 str_day[2] = 0;
1675
1676 StrCpy(str_hour, sizeof(str_hour), tmp + 11);
1677 str_hour[2] = 0;
1678
1679 StrCpy(str_minute, sizeof(str_minute), tmp + 14);
1680 str_minute[2] = 0;
1681
1682 StrCpy(str_second, sizeof(str_second), tmp + 17);
1683 str_second[2] = 0;
1684
1685 str_msec[0] = 0;
1686
1687 if (StrLen(tmp) >= 21 && tmp[19] == '.')
1688 {
1689 StrCpy(str_msec, sizeof(str_msec), tmp + 20);
1690 str_msec[StrLen(tmp) - 21] = 0;
1691 while (StrLen(str_msec) < 3)
1692 {
1693 StrCat(str_msec, sizeof(str_msec), "0");
1694 }
1695 str_msec[3] = 0;
1696 }
1697
1698 st->wYear = ToInt(str_year);
1699 st->wMonth = ToInt(str_month);
1700 st->wDay = ToInt(str_day);
1701 st->wHour = ToInt(str_hour);
1702 st->wMinute = ToInt(str_minute);
1703 st->wSecond = ToInt(str_second);
1704 st->wMilliseconds = ToInt(str_msec);
1705
1706 NormalizeSystem(st);
1707
1708 ok = true;
1709 }
1710 }
1711
1712 return ok;
1713 }
1714
1715 // Get the date and time string in RFC3339 format (example: 2017-09-27T18:25:55.434-9:00)
GetDateTimeStrRFC3339(char * str,UINT size,SYSTEMTIME * st,int timezone_min)1716 void GetDateTimeStrRFC3339(char *str, UINT size, SYSTEMTIME *st, int timezone_min){
1717 // Validate arguments
1718 if (str == NULL || st == NULL)
1719 {
1720 ClearStr(str, size);
1721 return;
1722 }
1723
1724 if(timezone_min == 0){
1725 Format(str, size, "%04u-%02u-%02uT%02u:%02u:%02u.%03uZ",
1726 st->wYear, st->wMonth, st->wDay,
1727 st->wHour, st->wMinute, st->wSecond,
1728 st->wMilliseconds);
1729 }else{
1730 Format(str, size, "%04u-%02u-%02uT%02u:%02u:%02u.%03u%+02d:%02d",
1731 st->wYear, st->wMonth, st->wDay,
1732 st->wHour, st->wMinute, st->wSecond,
1733 st->wMilliseconds, timezone_min/60, timezone_min%60);
1734 }
1735 }
1736
1737 // Get the time string
GetSpanStr(char * str,UINT size,UINT64 sec64)1738 void GetSpanStr(char *str, UINT size, UINT64 sec64)
1739 {
1740 char tmp[MAX_SIZE];
1741 // Validate arguments
1742 if (str == NULL)
1743 {
1744 return;
1745 }
1746
1747 StrCpy(tmp, sizeof(tmp), "");
1748 if (sec64 >= (UINT64)(1000 * 3600 * 24))
1749 {
1750 Format(tmp, sizeof(tmp), "%u:", (UINT)(sec64 / (UINT64)(1000 * 3600 * 24)));
1751 }
1752
1753 Format(tmp, sizeof(tmp), "%s%02u:%02u:%02u", tmp,
1754 (UINT)(sec64 % (UINT64)(1000 * 60 * 60 * 24)) / (1000 * 60 * 60),
1755 (UINT)(sec64 % (UINT64)(1000 * 60 * 60)) / (1000 * 60),
1756 (UINT)(sec64 % (UINT64)(1000 * 60)) / 1000);
1757
1758 Trim(tmp);
1759 StrCpy(str, size, tmp);
1760 }
1761
1762 // Get the time string (in milliseconds)
GetSpanStrMilli(char * str,UINT size,UINT64 sec64)1763 void GetSpanStrMilli(char *str, UINT size, UINT64 sec64)
1764 {
1765 char tmp[MAX_SIZE];
1766 // Validate arguments
1767 if (str == NULL)
1768 {
1769 return;
1770 }
1771
1772 StrCpy(tmp, sizeof(tmp), "");
1773 if (sec64 >= (UINT64)(1000 * 3600 * 24))
1774 {
1775 Format(tmp, sizeof(tmp), "%u:", (UINT)(sec64 / (UINT64)(1000 * 3600 * 24)));
1776 }
1777
1778 Format(tmp, sizeof(tmp), "%s%02u:%02u:%02u.%03u", tmp,
1779 (UINT)(sec64 % (UINT64)(1000 * 60 * 60 * 24)) / (1000 * 60 * 60),
1780 (UINT)(sec64 % (UINT64)(1000 * 60 * 60)) / (1000 * 60),
1781 (UINT)(sec64 % (UINT64)(1000 * 60)) / 1000,
1782 (UINT)(sec64 % (UINT64)(1000)));
1783
1784 Trim(tmp);
1785 StrCpy(str, size, tmp);
1786 }
1787
1788 // Get the time string (extended)
GetSpanStrEx(wchar_t * str,UINT size,UINT64 sec64,LOCALE * locale)1789 void GetSpanStrEx(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)
1790 {
1791 wchar_t tmp[MAX_SIZE];
1792 // Validate arguments
1793 if (str == NULL)
1794 {
1795 return;
1796 }
1797
1798 locale = (locale != NULL ? locale : ¤t_locale);
1799
1800 UniStrCpy(tmp, sizeof(tmp), L"");
1801 if (sec64 >= (UINT64)(1000 * 3600 * 24))
1802 {
1803 UniFormat(tmp, sizeof(tmp), L"%u%s ", (UINT)(sec64 / (UINT64)(1000 * 3600 * 24)),
1804 locale->SpanDay);
1805 }
1806
1807 UniFormat(tmp, sizeof(tmp), L"%s%u%s %02u%s %02u%s", tmp,
1808 (UINT)(sec64 % (UINT64)(1000 * 60 * 60 * 24)) / (1000 * 60 * 60),
1809 locale->SpanHour,
1810 (UINT)(sec64 % (UINT64)(1000 * 60 * 60)) / (1000 * 60),
1811 locale->SpanMinute,
1812 (UINT)(sec64 % (UINT64)(1000 * 60)) / 1000,
1813 locale->SpanSecond);
1814
1815 UniTrim(tmp);
1816 UniStrCpy(str, size, tmp);
1817 }
1818
1819 // Get the current locale information
GetCurrentLocale(LOCALE * locale)1820 void GetCurrentLocale(LOCALE *locale)
1821 {
1822 // Validate arguments
1823 if (locale == NULL)
1824 {
1825 return;
1826 }
1827
1828 Copy(locale, ¤t_locale, sizeof(LOCALE));
1829 }
1830
1831 // Set the locale information
SetLocale(wchar_t * str)1832 void SetLocale(wchar_t *str)
1833 {
1834 wchar_t *set_locale_str;
1835 LOCALE tmp;
1836
1837 if (str != NULL)
1838 {
1839 set_locale_str = str;
1840 }
1841 else
1842 {
1843 set_locale_str = default_locale_str;
1844 }
1845
1846 if (LoadLocale(&tmp, set_locale_str) == false)
1847 {
1848 if (LoadLocale(&tmp, default_locale_str) == false)
1849 {
1850 return;
1851 }
1852 }
1853
1854 Copy(¤t_locale, &tmp, sizeof(LOCALE));
1855 }
1856
1857 #define COPY_LOCALE_STR(dest, size, src) UniStrCpy(dest, size, UniStrCmp(src, L"$") == 0 ? L"" : src)
1858
1859 // Read the locale information
LoadLocale(LOCALE * locale,wchar_t * str)1860 bool LoadLocale(LOCALE *locale, wchar_t *str)
1861 {
1862 UNI_TOKEN_LIST *tokens;
1863 UINT i;
1864 // Validate arguments
1865 if (locale == NULL || str == NULL)
1866 {
1867 return false;
1868 }
1869
1870 // Analysis of the token
1871 tokens = UniParseToken(str, L" ");
1872 if (tokens->NumTokens != 18)
1873 {
1874 UniFreeToken(tokens);
1875 return false;
1876 }
1877
1878 // Set to the structure
1879 Zero(locale, sizeof(LOCALE));
1880 COPY_LOCALE_STR(locale->YearStr, sizeof(locale->YearStr), tokens->Token[0]);
1881 COPY_LOCALE_STR(locale->MonthStr, sizeof(locale->MonthStr), tokens->Token[1]);
1882 COPY_LOCALE_STR(locale->DayStr, sizeof(locale->DayStr), tokens->Token[2]);
1883 COPY_LOCALE_STR(locale->HourStr, sizeof(locale->HourStr), tokens->Token[3]);
1884 COPY_LOCALE_STR(locale->MinuteStr, sizeof(locale->MinuteStr), tokens->Token[4]);
1885 COPY_LOCALE_STR(locale->SecondStr, sizeof(locale->SecondStr), tokens->Token[5]);
1886
1887 for (i = 0;i < 7;i++)
1888 {
1889 COPY_LOCALE_STR(locale->DayOfWeek[i], sizeof(locale->DayOfWeek[i]),
1890 tokens->Token[6 + i]);
1891 }
1892
1893 COPY_LOCALE_STR(locale->SpanDay, sizeof(locale->SpanDay), tokens->Token[13]);
1894 COPY_LOCALE_STR(locale->SpanHour, sizeof(locale->SpanHour), tokens->Token[14]);
1895 COPY_LOCALE_STR(locale->SpanMinute, sizeof(locale->SpanMinute), tokens->Token[15]);
1896 COPY_LOCALE_STR(locale->SpanSecond, sizeof(locale->SpanSecond), tokens->Token[16]);
1897
1898 COPY_LOCALE_STR(locale->Unknown, sizeof(locale->Unknown), tokens->Token[17]);
1899
1900 UniFreeToken(tokens);
1901 return true;
1902 }
1903
1904 // Convert SYSTEMTIME into DOS date
SystemToDosDate(SYSTEMTIME * st)1905 USHORT SystemToDosDate(SYSTEMTIME *st)
1906 {
1907 return (USHORT)(
1908 ((UINT)(st->wYear - 1980) << 9) |
1909 ((UINT)st->wMonth<< 5) |
1910 (UINT)st->wDay);
1911 }
System64ToDosDate(UINT64 i)1912 USHORT System64ToDosDate(UINT64 i)
1913 {
1914 SYSTEMTIME st;
1915 UINT64ToSystem(&st, i);
1916 return SystemToDosDate(&st);
1917 }
1918
1919 // Convert SYSTEMTIME into DOS time
SystemToDosTime(SYSTEMTIME * st)1920 USHORT SystemToDosTime(SYSTEMTIME *st)
1921 {
1922 return (USHORT)(
1923 ((UINT)st->wHour << 11) |
1924 ((UINT)st->wMinute << 5) |
1925 ((UINT)st->wSecond >> 1));
1926 }
System64ToDosTime(UINT64 i)1927 USHORT System64ToDosTime(UINT64 i)
1928 {
1929 SYSTEMTIME st;
1930 UINT64ToSystem(&st, i);
1931 return SystemToDosTime(&st);
1932 }
1933
1934 // Convert the tm to the SYSTEMTIME
TmToSystem(SYSTEMTIME * st,struct tm * t)1935 void TmToSystem(SYSTEMTIME *st, struct tm *t)
1936 {
1937 struct tm tmp;
1938 // Validate arguments
1939 if (st == NULL || t == NULL)
1940 {
1941 return;
1942 }
1943
1944 Copy(&tmp, t, sizeof(struct tm));
1945 NormalizeTm(&tmp);
1946
1947 Zero(st, sizeof(SYSTEMTIME));
1948 st->wYear = MAKESURE(tmp.tm_year + 1900, 1970, 2099);
1949 st->wMonth = MAKESURE(tmp.tm_mon + 1, 1, 12);
1950 st->wDay = MAKESURE(tmp.tm_mday, 1, 31);
1951 st->wDayOfWeek = MAKESURE(tmp.tm_wday, 0, 6);
1952 st->wHour = MAKESURE(tmp.tm_hour, 0, 23);
1953 st->wMinute = MAKESURE(tmp.tm_min, 0, 59);
1954 st->wSecond = MAKESURE(tmp.tm_sec, 0, 59);
1955 st->wMilliseconds = 0;
1956 }
1957
1958 // Convert the SYSTEMTIME to tm
SystemToTm(struct tm * t,SYSTEMTIME * st)1959 void SystemToTm(struct tm *t, SYSTEMTIME *st)
1960 {
1961 // Validate arguments
1962 if (t == NULL || st == NULL)
1963 {
1964 return;
1965 }
1966
1967 Zero(t, sizeof(struct tm));
1968 t->tm_year = MAKESURE(st->wYear, 1970, 2099) - 1900;
1969 t->tm_mon = MAKESURE(st->wMonth, 1, 12) - 1;
1970 t->tm_mday = MAKESURE(st->wDay, 1, 31);
1971 t->tm_hour = MAKESURE(st->wHour, 0, 23);
1972 t->tm_min = MAKESURE(st->wMinute, 0, 59);
1973 t->tm_sec = MAKESURE(st->wSecond, 0, 59);
1974
1975 t->tm_isdst = -1;
1976 NormalizeTm(t);
1977 }
1978
1979 // Convert the time_t to SYSTEMTIME
TimeToSystem(SYSTEMTIME * st,time_64t t)1980 void TimeToSystem(SYSTEMTIME *st, time_64t t)
1981 {
1982 struct tm tmp;
1983 // Validate arguments
1984 if (st == NULL)
1985 {
1986 return;
1987 }
1988
1989 TimeToTm(&tmp, t);
1990 TmToSystem(st, &tmp);
1991 }
1992
1993 // Convert the time_t to 64-bit SYSTEMTIME
TimeToSystem64(time_64t t)1994 UINT64 TimeToSystem64(time_64t t)
1995 {
1996 SYSTEMTIME st;
1997
1998 TimeToSystem(&st, t);
1999
2000 return SystemToUINT64(&st);
2001 }
2002
2003 // Convert the SYSTEMTIME to time_t
SystemToTime(SYSTEMTIME * st)2004 time_64t SystemToTime(SYSTEMTIME *st)
2005 {
2006 struct tm t;
2007 // Validate arguments
2008 if (st == NULL)
2009 {
2010 return 0;
2011 }
2012
2013 SystemToTm(&t, st);
2014 return TmToTime(&t);
2015 }
2016
2017 // Convert a 64-bit SYSTEMTIME to a time_t
System64ToTime(UINT64 i)2018 time_64t System64ToTime(UINT64 i)
2019 {
2020 SYSTEMTIME st;
2021
2022 UINT64ToSystem(&st, i);
2023
2024 return SystemToTime(&st);
2025 }
2026
2027 // Convert the tm to time_t
TmToTime(struct tm * t)2028 time_64t TmToTime(struct tm *t)
2029 {
2030 time_64t tmp;
2031 // Validate arguments
2032 if (t == NULL)
2033 {
2034 return 0;
2035 }
2036
2037 tmp = c_mkgmtime(t);
2038 if (tmp == (time_64t)-1)
2039 {
2040 return 0;
2041 }
2042 return tmp;
2043 }
2044
2045 // Convert time_t to tm
TimeToTm(struct tm * t,time_64t time)2046 void TimeToTm(struct tm *t, time_64t time)
2047 {
2048 // Validate arguments
2049 if (t == NULL)
2050 {
2051 return;
2052 }
2053
2054 Zero(t, sizeof(struct tm));
2055 c_gmtime_r(&time, t);
2056 }
2057
2058 // Normalize the tm
NormalizeTm(struct tm * t)2059 void NormalizeTm(struct tm *t)
2060 {
2061 time_64t tmp;
2062 // Validate arguments
2063 if (t == NULL)
2064 {
2065 return;
2066 }
2067
2068 tmp = c_mkgmtime(t);
2069 if (tmp == (time_64t)-1)
2070 {
2071 return;
2072 }
2073
2074 c_gmtime_r(&tmp, t);
2075 }
2076
2077 // Normalize the SYSTEMTIME
NormalizeSystem(SYSTEMTIME * st)2078 void NormalizeSystem(SYSTEMTIME *st)
2079 {
2080 UINT64 sec64;
2081 // Validate arguments
2082 if (st == NULL)
2083 {
2084 return;
2085 }
2086
2087 sec64 = SystemToUINT64(st);
2088 UINT64ToSystem(st, sec64);
2089 }
2090
2091 // Convert a 64-bit local time to a system time
LocalToSystem64(UINT64 t)2092 UINT64 LocalToSystem64(UINT64 t)
2093 {
2094 SYSTEMTIME st;
2095 UINT64ToSystem(&st, t);
2096 LocalToSystem(&st, &st);
2097 return SystemToUINT64(&st);
2098 }
2099
2100 // Convert the 64bit system time to local time
SystemToLocal64(UINT64 t)2101 UINT64 SystemToLocal64(UINT64 t)
2102 {
2103 SYSTEMTIME st;
2104 UINT64ToSystem(&st, t);
2105 SystemToLocal(&st, &st);
2106 return SystemToUINT64(&st);
2107 }
2108
2109 // Convert local time to system time
LocalToSystem(SYSTEMTIME * system,SYSTEMTIME * local)2110 void LocalToSystem(SYSTEMTIME *system, SYSTEMTIME *local)
2111 {
2112 UINT64 sec64;
2113 // Validate arguments
2114 if (local == NULL || system == NULL)
2115 {
2116 return;
2117 }
2118
2119 sec64 = (UINT64)((INT64)SystemToUINT64(local) - GetTimeDiffEx(local, true));
2120 UINT64ToSystem(system, sec64);
2121 }
2122
2123 // Convert the system time to local time
SystemToLocal(SYSTEMTIME * local,SYSTEMTIME * system)2124 void SystemToLocal(SYSTEMTIME *local, SYSTEMTIME *system)
2125 {
2126 UINT64 sec64;
2127 // Validate arguments
2128 if (local == NULL || system == NULL)
2129 {
2130 return;
2131 }
2132
2133 sec64 = (UINT64)((INT64)SystemToUINT64(system) + GetTimeDiffEx(system, false));
2134 UINT64ToSystem(local, sec64);
2135 }
2136
2137 // Get the time difference between the local time and the system time based on the specified time
GetTimeDiffEx(SYSTEMTIME * basetime,bool local_time)2138 INT64 GetTimeDiffEx(SYSTEMTIME *basetime, bool local_time)
2139 {
2140 time_t tmp;
2141 struct tm t1, t2;
2142 SYSTEMTIME snow;
2143 struct tm now;
2144 SYSTEMTIME s1, s2;
2145 INT64 ret;
2146
2147 Copy(&snow, basetime, sizeof(SYSTEMTIME));
2148
2149 if (sizeof(time_t) == 4)
2150 {
2151 if (snow.wYear >= 2038)
2152 {
2153 // For old systems: avoid the 2038-year problem
2154 snow.wYear = 2037;
2155 }
2156 }
2157
2158 SystemToTm(&now, &snow);
2159 if (local_time == false)
2160 {
2161 tmp = (time_t)c_mkgmtime(&now);
2162 }
2163 else
2164 {
2165 tmp = mktime(&now);
2166 }
2167
2168 if (tmp == (time_t)-1)
2169 {
2170 return 0;
2171 }
2172
2173 #ifndef OS_UNIX
2174 Copy(&t1, localtime(&tmp), sizeof(struct tm));
2175 Copy(&t2, gmtime(&tmp), sizeof(struct tm));
2176 #else // OS_UNIX
2177 localtime_r(&tmp, &t1);
2178 gmtime_r(&tmp, &t2);
2179 #endif // OS_UNIX
2180
2181 TmToSystem(&s1, &t1);
2182 TmToSystem(&s2, &t2);
2183
2184 ret = (INT)SystemToUINT64(&s1) - (INT)SystemToUINT64(&s2);
2185
2186 return ret;
2187 }
2188
2189 // Convert UINT64 to the SYSTEMTIME
UINT64ToSystem(SYSTEMTIME * st,UINT64 sec64)2190 void UINT64ToSystem(SYSTEMTIME *st, UINT64 sec64)
2191 {
2192 UINT64 tmp64;
2193 UINT sec, millisec;
2194 time_64t time;
2195 // Validate arguments
2196 if (st == NULL)
2197 {
2198 return;
2199 }
2200
2201 sec64 = SafeTime64(sec64 + 32400000ULL);
2202 tmp64 = sec64 / (UINT64)1000;
2203 millisec = (UINT)(sec64 - tmp64 * (UINT64)1000);
2204 sec = (UINT)tmp64;
2205 time = (time_64t)sec;
2206 TimeToSystem(st, time);
2207 st->wMilliseconds = (WORD)millisec;
2208 }
2209
2210 // Convert the SYSTEMTIME to UINT64
SystemToUINT64(SYSTEMTIME * st)2211 UINT64 SystemToUINT64(SYSTEMTIME *st)
2212 {
2213 UINT64 sec64;
2214 time_64t time;
2215 // Validate arguments
2216 if (st == NULL)
2217 {
2218 return 0;
2219 }
2220
2221 time = SystemToTime(st);
2222
2223 //For times before 1970-01-01, clamp to the minimum
2224 //because we have to return an unsigned integer.
2225 //This is less wrong than casting it to UINT64
2226 //and returning a time far in the future.
2227 //For some reason we subtract 9 hours below, so
2228 //account for that here.
2229 if( time < 32400000LL ) return 0;
2230
2231 sec64 = (UINT64)time * (UINT64)1000;
2232 sec64 += st->wMilliseconds;
2233
2234 return sec64 - 32400000ULL;
2235 }
2236
2237 // Get local time in UINT64
LocalTime64()2238 UINT64 LocalTime64()
2239 {
2240 SYSTEMTIME s;
2241 LocalTime(&s);
2242 return SystemToUINT64(&s);
2243 }
2244
2245 // Get the system time in UINT64
SystemTime64()2246 UINT64 SystemTime64()
2247 {
2248 SYSTEMTIME s;
2249 SystemTime(&s);
2250 return SystemToUINT64(&s);
2251 }
2252
2253 // Get local time
LocalTime(SYSTEMTIME * st)2254 void LocalTime(SYSTEMTIME *st)
2255 {
2256 SYSTEMTIME tmp;
2257 // Validate arguments
2258 if (st == NULL)
2259 {
2260 return;
2261 }
2262
2263 SystemTime(&tmp);
2264 SystemToLocal(st, &tmp);
2265 }
2266
2267 // Get the System Time
SystemTime(SYSTEMTIME * st)2268 void SystemTime(SYSTEMTIME *st)
2269 {
2270 // Validate arguments
2271 if (st == NULL)
2272 {
2273 return;
2274 }
2275
2276 OSGetSystemTime(st);
2277
2278 // KS
2279 KS_INC(KS_GETTIME_COUNT);
2280 }
2281
c_mkgmtime(struct tm * tm)2282 time_64t c_mkgmtime(struct tm *tm)
2283 {
2284 int years, months, days, hours, minutes, seconds;
2285
2286 years = tm->tm_year + 1900; /* year - 1900 -> year */
2287 months = tm->tm_mon; /* 0..11 */
2288 days = tm->tm_mday - 1; /* 1..31 -> 0..30 */
2289 hours = tm->tm_hour; /* 0..23 */
2290 minutes = tm->tm_min; /* 0..59 */
2291 seconds = tm->tm_sec; /* 0..61 in ANSI C. */
2292
2293 ADJUST_TM(seconds, minutes, 60);
2294 ADJUST_TM(minutes, hours, 60);
2295 ADJUST_TM(hours, days, 24);
2296 ADJUST_TM(months, years, 12);
2297 if (days < 0)
2298 do {
2299 if (--months < 0) {
2300 --years;
2301 months = 11;
2302 }
2303 days += monthlen(months, years);
2304 } while (days < 0);
2305 else
2306 while (days >= monthlen(months, years)) {
2307 days -= monthlen(months, years);
2308 if (++months >= 12) {
2309 ++years;
2310 months = 0;
2311 }
2312 }
2313
2314 /* Restore adjusted values in tm structure */
2315 tm->tm_year = years - 1900;
2316 tm->tm_mon = months;
2317 tm->tm_mday = days + 1;
2318 tm->tm_hour = hours;
2319 tm->tm_min = minutes;
2320 tm->tm_sec = seconds;
2321
2322 /* Set `days' to the number of days into the year. */
2323 days += ydays[months] + (months > 1 && leap (years));
2324 tm->tm_yday = days;
2325
2326 /* Now calculate `days' to the number of days since Jan 1, 1970. */
2327 days = (unsigned)days + 365 * (unsigned)(years - 1970) +
2328 (unsigned)(nleap (years));
2329 tm->tm_wday = ((unsigned)days + 4) % 7; /* Jan 1, 1970 was Thursday. */
2330 tm->tm_isdst = 0;
2331
2332 if (years < 1970)
2333 return (time_64t)-1;
2334
2335 #if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX))
2336 #if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX))
2337 if (years > TM_YEAR_MAX ||
2338 (years == TM_YEAR_MAX &&
2339 (tm->tm_yday > ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +
2340 (TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) ||
2341 (tm->tm_yday == ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +
2342 (TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) &&
2343 (hours > TM_HOUR_MAX ||
2344 (hours == TM_HOUR_MAX &&
2345 (minutes > TM_MIN_MAX ||
2346 (minutes == TM_MIN_MAX && seconds > TM_SEC_MAX) )))))))
2347 return (time_64t)-1;
2348 #endif
2349 #endif
2350
2351 return (time_64t)(86400L * (unsigned long)(unsigned)days +
2352 3600L * (unsigned long)hours +
2353 (unsigned long)(60 * minutes + seconds));
2354 }
2355
2356 // Get the system timer
Tick()2357 UINT Tick()
2358 {
2359 // KS
2360 KS_INC(KS_GETTICK_COUNT);
2361 return OSGetTick();
2362 }
2363
2364 // Sleep thread
SleepThread(UINT time)2365 void SleepThread(UINT time)
2366 {
2367 // KS
2368 KS_INC(KS_SLEEPTHREAD_COUNT);
2369
2370 OSSleep(time);
2371 }
2372
2373 // Yield
YieldCpu()2374 void YieldCpu()
2375 {
2376 OSYield();
2377 }
2378
2379 // Stop system (abnormal termination)
AbortExit()2380 void AbortExit()
2381 {
2382 #ifdef OS_WIN32
2383 _exit(1);
2384 #else // OS_WIN32
2385
2386 #ifdef RLIMIT_CORE
2387 UnixSetResourceLimit(RLIMIT_CORE, 0);
2388 #endif // RLIMIT_CORE
2389
2390 abort();
2391 #endif // OS_WIN32
2392 }
2393
2394
AbortExitEx(char * msg)2395 void AbortExitEx(char *msg)
2396 {
2397 FILE *f;
2398 // Validate arguments
2399 if (msg == NULL)
2400 {
2401 msg = "Unknown Error";
2402 }
2403
2404 f = fopen("abort_error_log.txt", "w");
2405 if (f != NULL)
2406 {
2407 fwrite(msg, 1, strlen(msg), f);
2408 fclose(f);
2409 }
2410
2411 fputs("Fatal Error: ", stdout);
2412 fputs(msg, stdout);
2413 fputs("\r\n", stdout);
2414
2415 #ifdef OS_WIN32
2416 _exit(1);
2417 #else // OS_WIN32
2418
2419 #ifdef RLIMIT_CORE
2420 UnixSetResourceLimit(RLIMIT_CORE, 0);
2421 #endif // RLIMIT_CORE
2422
2423 abort();
2424 #endif // OS_WIN32
2425 }
2426
2427