// SoftEther VPN Source Code - Stable Edition Repository // Mayaqua Kernel // // SoftEther VPN Server, Client and Bridge are free software under the Apache License, Version 2.0. // // Copyright (c) Daiyuu Nobori. // Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan. // Copyright (c) SoftEther Corporation. // Copyright (c) all contributors on SoftEther VPN project in GitHub. // // All Rights Reserved. // // http://www.softether.org/ // // This stable branch is officially managed by Daiyuu Nobori, the owner of SoftEther VPN Project. // Pull requests should be sent to the Developer Edition Master Repository on https://github.com/SoftEtherVPN/SoftEtherVPN // // License: The Apache License, Version 2.0 // https://www.apache.org/licenses/LICENSE-2.0 // // DISCLAIMER // ========== // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN, UNDER // JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY, MERGE, PUBLISH, // DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS SOFTWARE, THAT ANY // JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS SOFTWARE OR ITS CONTENTS, // AGAINST US (SOFTETHER PROJECT, SOFTETHER CORPORATION, DAIYUU NOBORI OR OTHER // SUPPLIERS), OR ANY JURIDICAL DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND // OF USING, COPYING, MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, // AND/OR SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND // CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO EXCLUSIVE // JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO, JAPAN. YOU MUST WAIVE // ALL DEFENSES OF LACK OF PERSONAL JURISDICTION AND FORUM NON CONVENIENS. // PROCESS MAY BE SERVED ON EITHER PARTY IN THE MANNER AUTHORIZED BY APPLICABLE // LAW OR COURT RULE. // // USE ONLY IN JAPAN. DO NOT USE THIS SOFTWARE IN ANOTHER COUNTRY UNLESS YOU HAVE // A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY CRIMINAL LAWS OR CIVIL // RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS SOFTWARE IN OTHER COUNTRIES IS // COMPLETELY AT YOUR OWN RISK. THE SOFTETHER VPN PROJECT HAS DEVELOPED AND // DISTRIBUTED THIS SOFTWARE TO COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING // CIVIL RIGHTS INCLUDING PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER // COUNTRIES' LAWS OR CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES. // WE HAVE NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR // INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+ COUNTRIES // AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE WORLD, WITH // DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY COUNTRIES' LAWS, REGULATIONS // AND CIVIL RIGHTS TO MAKE THE SOFTWARE COMPLY WITH ALL COUNTRIES' LAWS BY THE // PROJECT. EVEN IF YOU WILL BE SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A // PUBLIC SERVANT IN YOUR COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE // LIABLE TO RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL // RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT JUST A // STATEMENT FOR WARNING AND DISCLAIMER. // // READ AND UNDERSTAND THE 'WARNING.TXT' FILE BEFORE USING THIS SOFTWARE. // SOME SOFTWARE PROGRAMS FROM THIRD PARTIES ARE INCLUDED ON THIS SOFTWARE WITH // LICENSE CONDITIONS WHICH ARE DESCRIBED ON THE 'THIRD_PARTY.TXT' FILE. // // // SOURCE CODE CONTRIBUTION // ------------------------ // // Your contribution to SoftEther VPN Project is much appreciated. // Please send patches to us through GitHub. // Read the SoftEther VPN Patch Acceptance Policy in advance: // http://www.softether.org/5-download/src/9.patch // // // DEAR SECURITY EXPERTS // --------------------- // // If you find a bug or a security vulnerability please kindly inform us // about the problem immediately so that we can fix the security problem // to protect a lot of users around the world as soon as possible. // // Our e-mail address for security reports is: // softether-vpn-security [at] softether.org // // Please note that the above e-mail address is not a technical support // inquiry address. If you need technical assistance, please visit // http://www.softether.org/ and ask your question on the users forum. // // Thank you for your cooperation. // // // NO MEMORY OR RESOURCE LEAKS // --------------------------- // // The memory-leaks and resource-leaks verification under the stress // test has been passed before release this source code. // Mayaqua.c // Mayaqua Kernel program #include #include #include #include #include #include #include #include #include #include // Global variable bool g_memcheck; // Enable memory check bool g_debug; // Debug mode UINT64 kernel_status[NUM_KERNEL_STATUS]; // Kernel state UINT64 kernel_status_max[NUM_KERNEL_STATUS]; // Kernel state (maximum value) LOCK *kernel_status_lock[NUM_KERNEL_STATUS]; // Kernel state lock BOOL kernel_status_inited = false; // Kernel state initialization flag bool g_little_endian = true; char *cmdline = NULL; // Command line wchar_t *uni_cmdline = NULL; // Unicode command line // Static variable static char *exename = NULL; // EXE file name (ANSI) static wchar_t *exename_w = NULL; // EXE file name (Unicode) static TOKEN_LIST *cmdline_token = NULL; // Command line token static UNI_TOKEN_LIST *cmdline_uni_token = NULL; // Command line token (Unicode) static OS_INFO *os_info = NULL; // OS information static bool dot_net_mode = false; static bool minimal_mode = false; static UINT last_time_check = 0; static UINT first_time_check = 0; static bool is_nt = false; static bool is_ham_mode = false; static UINT init_mayaqua_counter = 0; static bool use_probe = false; static BUF *probe_buf = NULL; static LOCK *probe_lock = NULL; static UINT64 probe_start = 0; static UINT64 probe_last = 0; static bool probe_enabled = false; // The function which should be called once as soon as possible after the process is started static bool init_proc_once_flag = false; void InitProcessCallOnce() { InitProcessCallOnceEx(false); } void InitProcessCallOnceEx(int restricted_mode) { if (init_proc_once_flag == false) { init_proc_once_flag = true; #ifdef OS_WIN32 MsInitProcessCallOnce(restricted_mode); #endif // OS_WIN32 } } // Calculate the checksum USHORT CalcChecksum16(void *buf, UINT size) { int sum = 0; USHORT *addr = (USHORT *)buf; int len = (int)size; USHORT *w = addr; int nleft = len; USHORT answer = 0; while (nleft > 1) { USHORT ww = 0; Copy(&ww, w++, sizeof(USHORT)); sum += ww; nleft -= 2; } if (nleft == 1) { *(UCHAR *)(&answer) = *(UCHAR *)w; sum += answer; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return answer; } // Writing a probe with the data void WriteProbeData(char *filename, UINT line, char *str, void *data, UINT size) { char tmp[MAX_SIZE]; USHORT cs; if (IsProbeEnabled() == false) { return; } // Take a checksum of the data if (size != 0) { cs = CalcChecksum16(data, size); } else { cs = 0; } // Generating a String snprintf(tmp, sizeof(tmp), "\"%s\" (Size=%5u, Crc=0x%04X)", str, size, cs); WriteProbe(filename, line, tmp); } // Writing Probe void WriteProbe(char *filename, UINT line, char *str) { #ifdef OS_WIN32 char *s; char tmp[MAX_SIZE]; char tmp2[MAX_SIZE]; UINT64 now = 0; UINT64 time; if (IsProbeEnabled() == false) { return; } now = MsGetHiResCounter(); Lock(probe_lock); { UINT64 diff; time = MsGetHiResTimeSpanUSec(now - probe_start); diff = time - probe_last; if (time < probe_last) { diff = 0; } probe_last = time; ToStr64(tmp, time); MakeCharArray2(tmp2, ' ', (UINT)(MIN(12, (int)12 - (int)StrLen(tmp)))); WriteBuf(probe_buf, tmp2, StrLen(tmp2)); WriteBuf(probe_buf, tmp, StrLen(tmp)); s = " [+"; WriteBuf(probe_buf, s, StrLen(s)); ToStr64(tmp, diff); MakeCharArray2(tmp2, ' ', (UINT)(MIN(12, (int)12 - (int)StrLen(tmp)))); WriteBuf(probe_buf, tmp2, StrLen(tmp2)); WriteBuf(probe_buf, tmp, StrLen(tmp)); s = "] - "; WriteBuf(probe_buf, s, StrLen(s)); WriteBuf(probe_buf, filename, StrLen(filename)); s = "("; WriteBuf(probe_buf, s, StrLen(s)); ToStr64(tmp, (UINT64)line); WriteBuf(probe_buf, tmp, StrLen(tmp)); s = "): "; WriteBuf(probe_buf, s, StrLen(s)); WriteBuf(probe_buf, str, StrLen(str)); s = "\r\n"; WriteBuf(probe_buf, s, StrLen(s)); } Unlock(probe_lock); #endif // OS_WIN32 } // Initialization of Probe void InitProbe() { probe_buf = NewBuf(); probe_lock = NewLock(); probe_enabled = false; probe_start = 0; #ifdef OS_WIN32 probe_start = MsGetHiResCounter(); #endif // OS_WIN32 } // Release of Probe void FreeProbe() { if (probe_buf->Size >= 1) { SYSTEMTIME st; char filename[MAX_SIZE]; // Write all to the file MakeDirEx("@probe_log"); LocalTime(&st); snprintf(filename, sizeof(filename), "@probe_log/%04u%02u%02u_%02u%02u%02u.log", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); DumpBuf(probe_buf, filename); } FreeBuf(probe_buf); DeleteLock(probe_lock); } // Set enable / disable the Probe void EnableProbe(bool enable) { probe_enabled = enable; } // Get whether the Probe is enabled? bool IsProbeEnabled() { #ifndef USE_PROBE return false; #else // USE_PROBE return probe_enabled; #endif // USE_PROBE } // Set the Ham mode void SetHamMode() { is_ham_mode = true; } // Get whether in Ham mode bool IsHamMode() { return is_ham_mode; } // Display the time from the previous call to now void TimeCheck() { #ifdef OS_WIN32 UINT now, ret, total; now = Win32GetTick(); if (last_time_check == 0) { ret = 0; } else { ret = now - last_time_check; } last_time_check = now; if (first_time_check == 0) { first_time_check = now; } total = now - first_time_check; printf(" -- %3.3f / %3.3f\n", (double)ret / 1000.0f, (double)total / 1000.0f); #endif // OS_WIN32 } // Whether this system is IA64 bool IsIA64() { if (Is64() == false) { return false; } #ifndef MAYAQUA_IA_64 return false; #else // MAYAQUA_IA_64 return true; #endif // MAYAQUA_IA_64 } // Whether in x64 bool IsX64() { if (Is64() == false) { return false; } #ifndef MAYAQUA_IA_64 return true; #else // MAYAQUA_IA_64 return false; #endif // MAYAQUA_IA_64 } // Whether 64bit bool Is64() { #ifdef CPU_64 return true; #else // CPU_64 return false; #endif // CPU_64 } // Whether 32bit bool Is32() { return Is64() ? false : true; } // .NET mode void MayaquaDotNetMode() { dot_net_mode = true; } // Acquisition whether in .NET mode bool MayaquaIsDotNetMode() { return dot_net_mode; } // Check the endian void CheckEndian() { unsigned short test; UCHAR *buf; test = 0x1234; buf = (UCHAR *)&test; if (buf[0] == 0x12) { g_little_endian = false; } else { g_little_endian = true; } } // Minimize mode void MayaquaMinimalMode() { minimal_mode = true; } bool MayaquaIsMinimalMode() { return minimal_mode; } // Whether in NT bool IsNt() { return is_nt; } // Whether the Unicode is supported bool IsUnicode() { #ifdef OS_WIN32 // Windows return IsNt(); #else // OS_WIN32 // UNIX return true; #endif // OS_WIN32 } // Initialization of Mayaqua library void InitMayaqua(bool memcheck, bool debug, int argc, char **argv) { wchar_t tmp[MAX_PATH]; UCHAR hash[SHA1_SIZE]; if ((init_mayaqua_counter++) > 0) { return; } InitProcessCallOnce(); g_memcheck = memcheck; g_debug = debug; cmdline = NULL; if (dot_net_mode == false) { // Fail this for some reason when this is called this in .NET mode setbuf(stdout, NULL); } // Acquisition whether NT #ifdef OS_WIN32 is_nt = Win32IsNt(); #endif // OS_WIN32 // Check endian CheckEndian(); #ifdef OS_WIN32 _configthreadlocale(_DISABLE_PER_THREAD_LOCALE); #endif // OS_WIN32 // Set the locale information of the CRT to the Japanese setlocale(LC_ALL, ""); // Initialization of OS OSInit(); // Initialize the random number srand((UINT)SystemTime64()); tick_manual_lock = NewLock(); // Initialization of CRC32 InitCrc32(); // Initialization of the FIFO system InitFifo(); // Initialize the Kernel status InitKernelStatus(); // Initialize the tracking InitTracking(); // Initialization of thread pool InitThreading(); // Initialize the string library InitStringLibrary(); // Initialization of the locale information SetLocale(NULL); // Initialization of the crypt library InitCryptLibrary(); // Initialization of the real-time clock InitTick64(); // Initialize the network communication module InitNetwork(); // Initialization of the aquisition of the EXE file name InitGetExeName(argc >= 1 ? argv[0] : NULL); // Initialization of the command line string InitCommandLineStr(argc, argv); // Initialization of OS information InitOsInfo(); // Initialization of the operating system-specific module #ifdef OS_WIN32 MsInit(); // Microsoft Win32 #endif // OS_WIN32 // Initialization of the security token module InitSecure(); if (OSIsSupportedOs() == false) { // Abort exit(0); } // Initialization of HamCore file system InitHamcore(); // Initialization of string table routine InitTable(); if (exename == NULL) { // Executable file name exename = CopyStr("unknown"); } // Check whether the executable file name of themselves is found // (If not found, quit because this is started in strange path) GetExeNameW(tmp, sizeof(tmp)); if (IsFileExistsW(tmp) == false) { wchar_t tmp2[MAX_SIZE]; UniFormat(tmp2, sizeof(tmp2), L"Error: Executable binary file \"%s\" not found.\r\n\r\n" L"Please execute program with full path.\r\n", tmp); AlertW(tmp2, NULL); _exit(0); } CheckUnixTempDir(); // Initialization of Probe InitProbe(); // Initialization of Machine Hash GetCurrentMachineIpProcessHash(hash); // Reading Private IP file LoadPrivateIPFile(); } // Release of Mayaqua library void FreeMayaqua() { if ((--init_mayaqua_counter) > 0) { return; } // Release of Private IP File FreePrivateIPFile(); // Release of Probe FreeProbe(); // Delete the table FreeTable(); // Release of security token module FreeSecure(); // Release of the operating system specific module #ifdef OS_WIN32 MsFree(); #endif // OS_WIN32 // Release of OS information FreeOsInfo(); // Release of HamCore file system FreeHamcore(); // Release of the command line string FreeCommandLineStr(); // Release of the command line token FreeCommandLineTokens(); // Release of network communication module FreeNetwork(); // Release of real-time clock FreeTick64(); // Release of crypt library FreeCryptLibrary(); // Release of the string library FreeStringLibrary(); // Release of thread pool FreeThreading(); #ifndef VPN_SPEED // Show the kernel status if (g_debug) { PrintKernelStatus(); } // Display the debug information if (g_memcheck) { PrintDebugInformation(); } #endif // VPN_SPEED // Release the tracking FreeTracking(); // Release of the kernel status FreeKernelStatus(); DeleteLock(tick_manual_lock); tick_manual_lock = NULL; // Release of OS OSFree(); } // Check whether /tmp is available in the UNIX void CheckUnixTempDir() { if (OS_IS_UNIX(GetOsInfo()->OsType)) { char tmp[128], tmp2[64]; UINT64 now = SystemTime64(); IO *o; MakeDir("/tmp"); Format(tmp2, sizeof(tmp2), "%I64u", now); Format(tmp, sizeof(tmp), "/tmp/.%s", tmp2); o = FileCreate(tmp); if (o == NULL) { o = FileOpen(tmp, false); if (o == NULL) { Print("Unable to use /tmp.\n\n"); exit(0); return; } } FileClose(o); FileDelete(tmp); } } // Show an alert void Alert(char *msg, char *caption) { OSAlert(msg, caption); } void AlertW(wchar_t *msg, wchar_t *caption) { OSAlertW(msg, caption); } // Display of OS information void PrintOsInfo(OS_INFO *info) { // Validate arguments if (info == NULL) { return; } Print( "OS Type : %u\n" "OS Service Pack : %u\n" "os_is_windows : %s\n" "os_is_windows_nt : %s\n" "OS System Name : %s\n" "OS Product Name : %s\n" "OS Vendor Name : %s\n" "OS Version : %s\n" "Kernel Name : %s\n" "Kernel Version : %s\n", info->OsType, info->OsServicePack, OS_IS_WINDOWS(info->OsType) ? "true" : "false", OS_IS_WINDOWS_NT(info->OsType) ? "true" : "false", info->OsSystemName, info->OsProductName, info->OsVendorName, info->OsVersion, info->KernelName, info->KernelVersion); #ifdef OS_WIN32 { char *exe, *dir; exe = MsGetExeFileName(); dir = MsGetExeDirName(); Print( "EXE File Path : %s\n" "EXE Dir Path : %s\n" "Process Id : %u\n" "Process Handle : 0x%X\n", exe, dir, MsGetCurrentProcessId(), MsGetCurrentProcess()); } #endif // OS_WIN32 } // Get the OS type UINT GetOsType() { OS_INFO *i = GetOsInfo(); if (i == NULL) { return 0; } return i->OsType; } // Getting OS information OS_INFO *GetOsInfo() { return os_info; } // Initialization of OS information void InitOsInfo() { if (os_info != NULL) { return; } os_info = ZeroMalloc(sizeof(OS_INFO)); OSGetOsInfo(os_info); } // Release of OS information void FreeOsInfo() { if (os_info == NULL) { return; } Free(os_info->OsSystemName); Free(os_info->OsProductName); Free(os_info->OsVendorName); Free(os_info->OsVersion); Free(os_info->KernelName); Free(os_info->KernelVersion); Free(os_info); os_info = NULL; } // Get the Unicode command line tokens UNI_TOKEN_LIST *GetCommandLineUniToken() { if (cmdline_uni_token == NULL) { return UniNullToken(); } else { return UniCopyToken(cmdline_uni_token); } } // Getting the command line tokens TOKEN_LIST *GetCommandLineToken() { if (cmdline_token == NULL) { return NullToken(); } else { return CopyToken(cmdline_token); } } // Convert the command line string into tokens void ParseCommandLineTokens() { if (cmdline_token != NULL) { FreeToken(cmdline_token); } cmdline_token = ParseCmdLine(cmdline); if (cmdline_uni_token != NULL) { UniFreeToken(cmdline_uni_token); } cmdline_uni_token = UniParseCmdLine(uni_cmdline); } // Release command line tokens void FreeCommandLineTokens() { if (cmdline_token != NULL) { FreeToken(cmdline_token); } cmdline_token = NULL; if (cmdline_uni_token != NULL) { UniFreeToken(cmdline_uni_token); } cmdline_uni_token = NULL; } // Initialization of the command line string void InitCommandLineStr(int argc, char **argv) { if (argc >= 1) { #ifdef OS_UNIX exename_w = CopyUtfToUni(argv[0]); exename = CopyUniToStr(exename_w); #else // OS_UNIX exename = CopyStr(argv[0]); exename_w = CopyStrToUni(exename); #endif // OS_UNIX } if (argc < 2 || argv == NULL) { // No command-line string SetCommandLineStr(NULL); } else { // There are command-line string int i, total_len = 1; char *tmp; for (i = 1;i < argc;i++) { total_len += StrLen(argv[i]) * 2 + 32; } tmp = ZeroMalloc(total_len); for (i = 1;i < argc;i++) { UINT s_size = StrLen(argv[i]) * 2; char *s = ZeroMalloc(s_size); bool dq = (SearchStrEx(argv[i], " ", 0, true) != INFINITE); ReplaceStrEx(s, s_size, argv[i], "\"", "\"\"", true); if (dq) { StrCat(tmp, total_len, "\""); } StrCat(tmp, total_len, s); if (dq) { StrCat(tmp, total_len, "\""); } StrCat(tmp, total_len, " "); Free(s); } Trim(tmp); SetCommandLineStr(tmp); Free(tmp); } } // Release of the command line string void FreeCommandLineStr() { SetCommandLineStr(NULL); if (exename != NULL) { Free(exename); exename = NULL; } if (exename_w != NULL) { Free(exename_w); exename_w = NULL; } } // Get the Unicode command line string wchar_t *GetCommandLineUniStr() { if (uni_cmdline == NULL) { return UniCopyStr(L""); } else { return UniCopyStr(uni_cmdline); } } // Get the command line string char *GetCommandLineStr() { if (cmdline == NULL) { return CopyStr(""); } else { return CopyStr(cmdline); } } // Set the Unicode command line string void SetCommandLineUniStr(wchar_t *str) { if (uni_cmdline != NULL) { Free(uni_cmdline); } if (str == NULL) { uni_cmdline = NULL; } else { uni_cmdline = CopyUniStr(str); } ParseCommandLineTokens(); } // Set the command-line string void SetCommandLineStr(char *str) { // Validate arguments if (str == NULL) { if (cmdline != NULL) { Free(cmdline); } cmdline = NULL; } else { if (cmdline != NULL) { Free(cmdline); } cmdline = CopyStr(str); } if (cmdline == NULL) { if (uni_cmdline != NULL) { Free(uni_cmdline); uni_cmdline = NULL; } } else { if (uni_cmdline != NULL) { Free(uni_cmdline); } uni_cmdline = CopyStrToUni(cmdline); } ParseCommandLineTokens(); } // Display the kernel status void PrintKernelStatus() { bool leaked = false; Print("\n"); Print( " --------- Mayaqua Kernel Status ---------\n" " Malloc Count ............... %u\n" " ReAlloc Count .............. %u\n" " Free Count ................. %u\n" " Total Memory Size .......... %I64u bytes\n" " * Current Memory Blocks ...... %u Blocks (Peek: %u)\n" " Total Memory Blocks ........ %u Blocks\n" " * Current MemPool Blocks ..... %u Blocks (Peek: %u)\n" " Total MemPool Mallocs ...... %u Mallocs\n" " Total MemPool ReAllocs ..... %u ReAllocs\n" " NewLock Count .............. %u\n" " DeleteLock Count ........... %u\n" " * Current Lock Objects ....... %u Objects\n" " * Current Locked Objects ..... %u Objects\n" " NewRef Count ............... %u\n" " FreeRef Count .............. %u\n" " * Current Ref Objects ........ %u Objects\n" " * Current Ref Count .......... %u Refs\n" " GetTime Count .............. %u\n" " GetTick Count .............. %u\n" " NewThread Count ............ %u\n" " FreeThread Count ........... %u\n" " * Current Threads ............ %u Threads\n" " Wait For Event Count ....... %u\n\n", KS_GET(KS_MALLOC_COUNT), KS_GET(KS_REALLOC_COUNT), KS_GET(KS_FREE_COUNT), KS_GET64(KS_TOTAL_MEM_SIZE), KS_GET(KS_CURRENT_MEM_COUNT), KS_GETMAX(KS_CURRENT_MEM_COUNT), KS_GET(KS_TOTAL_MEM_COUNT), KS_GET(KS_MEMPOOL_CURRENT_NUM), KS_GETMAX(KS_MEMPOOL_CURRENT_NUM), KS_GET(KS_MEMPOOL_MALLOC_COUNT), KS_GET(KS_MEMPOOL_REALLOC_COUNT), KS_GET(KS_NEWLOCK_COUNT), KS_GET(KS_DELETELOCK_COUNT), KS_GET(KS_CURRENT_LOCK_COUNT), KS_GET(KS_CURRENT_LOCKED_COUNT), KS_GET(KS_NEWREF_COUNT), KS_GET(KS_FREEREF_COUNT), KS_GET(KS_CURRENT_REF_COUNT), KS_GET(KS_CURRENT_REFED_COUNT), KS_GET(KS_GETTIME_COUNT), KS_GET(KS_GETTICK_COUNT), KS_GET(KS_NEWTHREAD_COUNT), KS_GET(KS_FREETHREAD_COUNT), KS_GET(KS_NEWTHREAD_COUNT) - KS_GET(KS_FREETHREAD_COUNT), KS_GET(KS_WAIT_COUNT) ); if (KS_GET(KS_CURRENT_MEM_COUNT) != 0 || KS_GET(KS_CURRENT_LOCK_COUNT) != 0 || KS_GET(KS_MEMPOOL_CURRENT_NUM) != 0 || KS_GET(KS_CURRENT_LOCKED_COUNT) != 0 || KS_GET(KS_CURRENT_REF_COUNT) != 0) { leaked = true; } if (leaked) { Print(" !!! MEMORY LEAKS DETECTED !!!\n\n"); if (g_memcheck == false) { GetLine(NULL, 0); } } else { Print(" @@@ NO MEMORY LEAKS @@@\n\n"); } } // Initialize Kernel status void InitKernelStatus() { UINT i; // Memory initialization Zero(kernel_status, sizeof(kernel_status)); Zero(kernel_status_max, sizeof(kernel_status_max)); // Lock initialization for (i = 0;i < NUM_KERNEL_STATUS;i++) { kernel_status_lock[i] = OSNewLock(); } kernel_status_inited = true; } // Release of the kernel status void FreeKernelStatus() { UINT i; kernel_status_inited = false; // Lock release for (i = 0;i < NUM_KERNEL_STATUS;i++) { OSDeleteLock(kernel_status_lock[i]); } } // Lock the kernel status void LockKernelStatus(UINT id) { // Validate arguments if (id >= NUM_KERNEL_STATUS) { return; } OSLock(kernel_status_lock[id]); } // Unlock the kernel status void UnlockKernelStatus(UINT id) { // Validate arguments if (id >= NUM_KERNEL_STATUS) { return; } OSUnlock(kernel_status_lock[id]); } // Display the debug information void PrintDebugInformation() { MEMORY_STATUS memory_status; GetMemoryStatus(&memory_status); // Header Print("====== " CEDAR_PRODUCT_STR " VPN System Debug Information ======\n"); // Memory information Print(" \n" " Number of Allocated Memory Blocks: %u\n" " Total Size of Allocated Memory Blocks: %u bytes\n", memory_status.MemoryBlocksNum, memory_status.MemorySize); // Footer Print("====================================================\n"); if (KS_GET(KS_CURRENT_MEM_COUNT) != 0 || KS_GET(KS_CURRENT_LOCK_COUNT) != 0 || KS_GET(KS_CURRENT_LOCKED_COUNT) != 0 || KS_GET(KS_CURRENT_REF_COUNT) != 0) { // Show a debug menu because memory leaks suspected MemoryDebugMenu(); } }