Ejemplo n.º 1
0
//MailSlot of flush DNS cache sender
bool WINAPI FlushDNSMailSlotSender(
	void)
{
//Create mailslot.
	HANDLE hFile = CreateFileW(MAILSLOT_NAME, GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		std::unique_lock<std::mutex> ScreenMutex(ScreenLock);
		fwprintf_s(stderr, L"Create mailslot error, error code is %lu.\n", GetLastError());

		return false;
	}

//Write into mailslot.
	DWORD cbWritten = 0;
	if (!WriteFile(hFile, MAILSLOT_MESSAGE_FLUSH_DNS, (DWORD)(lstrlenW(MAILSLOT_MESSAGE_FLUSH_DNS) + 1U) * sizeof(wchar_t), &cbWritten, nullptr))
	{
		std::unique_lock<std::mutex> ScreenMutex(ScreenLock);
		fwprintf_s(stderr, L"MailSlot write messages error, error code is %lu.\n", GetLastError());

		CloseHandle(hFile);
		return false;
	}

	CloseHandle(hFile);
	std::unique_lock<std::mutex> ScreenMutex(ScreenLock);
	fwprintf_s(stderr, L"Flush DNS cache message was sent successfully.\n");
	return true;
}
Ejemplo n.º 2
0
//Flush DNS cache
void __fastcall FlushAllDNSCache(
	void)
{
//Flush DNS cache in program.
	std::unique_lock<std::mutex> DNSCacheListMutex(DNSCacheListLock);
	DNSCacheList.clear();
	DNSCacheList.shrink_to_fit();
	DNSCacheListMutex.unlock();

//Flush DNS cache in system.
	std::unique_lock<std::mutex> ScreenMutex(ScreenLock);

#if defined(PLATFORM_WIN)
	system("ipconfig /flushdns 2>nul"); //All Windows version
	fwprintf_s(stderr, L"\n");
#elif defined(PLATFORM_LINUX)
	#if defined(PLATFORM_OPENWRT)
		system("/etc/init.d/dnsmasq restart 2>/dev/null"); //Dnsmasq manage DNS cache on OpenWrt
	#else
		auto Result = system("service nscd restart 2>/dev/null"); //Name Service Cache Daemon service
		Result = system("service dnsmasq restart 2>/dev/null"); //Dnsmasq service
		Result = system("rndc restart 2>/dev/null"); //Name server control utility of BIND(9.1.3 and older version)
		Result = system("rndc flush 2>/dev/null"); //Name server control utility of BIND(9.2.0 and newer version)
	#endif
#elif defined(PLATFORM_MACX)
//	system("lookupd -flushcache 2>/dev/null"); //Less than Mac OS X Tiger(10.4)
//	system("dscacheutil -flushcache 2>/dev/null"); //Mac OS X Leopard(10.5) and Snow Leopard(10.6)
	system("killall -HUP mDNSResponder 2>/dev/null"); //Mac OS X Lion(10.7), Mountain Lion(10.8) and Mavericks(10.9)
	system("discoveryutil mdnsflushcache 2>/dev/null"); //Mac OS X Yosemite(10.10) and newer version
#endif

	return;
}
Ejemplo n.º 3
0
//Catch Control-C exception from keyboard.
BOOL WINAPI CtrlHandler(
	const DWORD fdwCtrlType)
{
//Print to screen.
	if (GlobalRunningStatus.Console)
	{
		std::unique_lock<std::mutex> ScreenMutex(ScreenLock);
		switch (fdwCtrlType)
		{
			case CTRL_C_EVENT: //Handle the CTRL-C signal.
			{
				fwprintf_s(stderr, L"Get Control-C.\n");
			}break;
			case CTRL_BREAK_EVENT: //Handle the CTRL-Break signal.
			{
				fwprintf_s(stderr, L"Get Control-Break.\n");
			}break;
			default: //Handle other signals.
			{
				fwprintf_s(stderr, L"Get closing signal.\n");
			}break;
		}
	}

	return FALSE;
}
Ejemplo n.º 4
0
//Flush DNS cache FIFO sender
bool FlushDNSFIFOSender(
	void)
{
	int FileFIFO = open(FIFO_PATH_NAME, O_WRONLY|O_TRUNC|O_NONBLOCK, 0);
	if (FileFIFO > 0 && write(FileFIFO, FIFO_MESSAGE_FLUSH_DNS, strlen(FIFO_MESSAGE_FLUSH_DNS) + 1U) > 0)
	{
		std::unique_lock<std::mutex> ScreenMutex(ScreenLock);
		fwprintf(stderr, L"Flush DNS cache message was sent successfully.\n");
		close(FileFIFO);
	}
	else {
		std::unique_lock<std::mutex> ScreenMutex(ScreenLock);
		fwprintf(stderr, L"FIFO write messages error, error code is %d.\n", errno);

		return false;
	}

	return true;
}
Ejemplo n.º 5
0
//Flush DNS cache
void FlushDNSCache(
	const uint8_t *Domain)
{
//Flush DNS cache in program.
	std::unique_lock<std::mutex> DNSCacheListMutex(DNSCacheListLock);
	if (Domain == nullptr) //Flush all DNS cache.
	{
		DNSCacheList.clear();
	}
//Flush single domain cache.
	else {
		for (auto DNSCacheDataIter = DNSCacheList.begin();DNSCacheDataIter != DNSCacheList.end();)
		{
			if (DNSCacheDataIter->Domain == (const char *)Domain)
				DNSCacheDataIter = DNSCacheList.erase(DNSCacheDataIter);
			else 
				++DNSCacheDataIter;
		}
	}
	DNSCacheListMutex.unlock();

//Flush DNS cache in system.
	std::lock_guard<std::mutex> ScreenMutex(ScreenLock);
#if defined(PLATFORM_WIN)
	system("ipconfig /flushdns 2>nul"); //All Windows version
	fwprintf_s(stderr, L"\n");
#elif defined(PLATFORM_LINUX)
	#if defined(PLATFORM_OPENWRT)
		system("/etc/init.d/dnsmasq restart 2>/dev/null"); //Dnsmasq manage DNS cache on OpenWrt
	#else
		auto Result = system("service nscd restart 2>/dev/null"); //Name Service Cache Daemon service
		Result = system("service dnsmasq restart 2>/dev/null"); //Dnsmasq service
		Result = system("rndc restart 2>/dev/null"); //Name server control utility of BIND(9.1.3 and older version)
		Result = system("rndc flush 2>/dev/null"); //Name server control utility of BIND(9.2.0 and newer version)
	#endif
#elif defined(PLATFORM_MACX)
//	system("lookupd -flushcache 2>/dev/null"); //Less than Mac OS X Tiger(10.4)
//	system("dscacheutil -flushcache 2>/dev/null"); //Mac OS X Leopard(10.5) and Snow Leopard(10.6)
	system("killall -HUP mDNSResponder 2>/dev/null"); //Mac OS X Lion(10.7), Mountain Lion(10.8) and Mavericks(10.9)
	system("discoveryutil mdnsflushcache 2>/dev/null"); //Mac OS X Yosemite(10.10) and newer version
#endif

	return;
}
Ejemplo n.º 6
0
//Flush DNS cache FIFO sender
bool FlushDNSFIFOSender(
	const uint8_t *Domain)
{
//Message initialization
	std::string Message(FIFO_MESSAGE_FLUSH_DNS);
	if (Domain != nullptr)
	{
		Message.append(": ");
		Message.append((const char *)Domain);
	}

//Write into FIFO file.
	errno = 0;
	int FIFO_Handle = open(FIFO_PATH_NAME, O_WRONLY|O_TRUNC|O_NONBLOCK, 0);
	if (FIFO_Handle > 0)
	{
		if (write(FIFO_Handle, Message.c_str(), Message.length() + 1U) > 0)
		{
			close(FIFO_Handle);
			PrintToScreen(true, L"Flush DNS cache message was sent successfully.\n");

			return true;
		}
		else {
			close(FIFO_Handle);
		}
	}

//Print error log.
	std::lock_guard<std::mutex> ScreenMutex(ScreenLock);
	PrintToScreen(false, L"FIFO write messages error");
	if (errno > 0)
		PrintToScreen(false, L", error code is %d.\n", errno);
	else 
		PrintToScreen(false, L".\n");

	return false;
}
Ejemplo n.º 7
0
int wmain(
	int argc, 
	wchar_t* argv[])
{
#elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
int main(
	int argc, 
	char *argv[])
{
#endif

//Get commands.
	if (argc > 0)
	{
		if (!ReadCommand(argc, argv))
			return EXIT_SUCCESS;
	}
	else {
		return EXIT_FAILURE;
	}

//Read configuration file.
	if (!ReadParameter(true))
		return EXIT_FAILURE;

//DNSCurve initialization
#if defined(ENABLE_LIBSODIUM)
	if (Parameter.DNSCurve)
	{
		DNSCurveParameterModificating.SetToMonitorItem();

	//Encryption mode initialization
		if (DNSCurveParameter.IsEncryption)
			DNSCurveInit();
	}
#endif

//Mark Local DNS address to PTR Records, read Parameter(Monitor mode), IPFilter and Hosts.
	ParameterModificating.SetToMonitorItem();
	std::thread NetworkInformationMonitorThread(std::bind(NetworkInformationMonitor));
	NetworkInformationMonitorThread.detach();
	std::thread ReadParameterThread(std::bind(ReadParameter, false));
	ReadParameterThread.detach();
	std::thread ReadHostsThread(std::bind(ReadHosts));
	ReadHostsThread.detach();
	if (Parameter.OperationMode == LISTEN_MODE_CUSTOM || Parameter.DataCheck_Blacklist || Parameter.LocalRouting)
	{
		std::thread ReadIPFilterThread(std::bind(ReadIPFilter));
		ReadIPFilterThread.detach();
	}

#if defined(PLATFORM_WIN)
//Service initialization and start service.
	SERVICE_TABLE_ENTRYW ServiceTable[]{{SYSTEM_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTIONW)ServiceMain}, {nullptr, nullptr}};
	if (!StartServiceCtrlDispatcherW(ServiceTable))
	{
		GlobalRunningStatus.Console = true;
		auto ErrorCode = GetLastError();
		
	//Print to screen.
		std::unique_lock<std::mutex> ScreenMutex(ScreenLock);
		fwprintf_s(stderr, L"System Error: Service start error, error code is %lu.\n", ErrorCode);
		fwprintf_s(stderr, L"System Error: Program will continue to run in console mode.\n");
		fwprintf_s(stderr, L"Please ignore these error messages if you want to run in console mode.\n\n");
		ScreenMutex.unlock();

	//Handle the system signal and start all monitors.
		SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
		MonitorInit();
	}
#elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
	MonitorInit();
#endif

	return EXIT_SUCCESS;
}

//Read commands from main program
#if defined(PLATFORM_WIN)
bool __fastcall ReadCommand(
	int argc, 
	wchar_t *argv[])
#elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
bool ReadCommand(
	int argc, 
	char *argv[])
#endif
{
//Path initialization
#if defined(PLATFORM_WIN)
	if (!FileNameInit(argv[0]))
		return false;
#elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
	char FileName[PATH_MAX + 1U] = {0};
	if (getcwd(FileName, PATH_MAX) == nullptr)
	{
		std::unique_lock<std::mutex> ScreenMutex(ScreenLock);
		fwprintf(stderr, L"Path initialization error.\n");

		return false;
	}
	if (!FileNameInit(FileName))
		return false;
#endif

//Screen output buffer setting
	if (setvbuf(stderr, NULL, _IONBF, 0) != 0)
	{
		auto ErrorCode = errno;
		std::unique_lock<std::mutex> ScreenMutex(ScreenLock);
		fwprintf_s(stderr, L"Screen output buffer setting error, error code is %d.\n", ErrorCode);
		ScreenLock.unlock();
		PrintError(LOG_LEVEL_2, LOG_ERROR_NETWORK, L"Screen output buffer setting error", ErrorCode, nullptr, 0);

		return false;
	}

//Winsock initialization
#if defined(PLATFORM_WIN)
	WSAData WSAInitialization = {0};
	if (WSAStartup(MAKEWORD(WINSOCK_VERSION_HIGH, WINSOCK_VERSION_LOW), &WSAInitialization) != 0 || 
		LOBYTE(WSAInitialization.wVersion) != WINSOCK_VERSION_LOW || HIBYTE(WSAInitialization.wVersion) != WINSOCK_VERSION_HIGH)
	{
		auto ErrorCode = WSAGetLastError();
		std::unique_lock<std::mutex> ScreenMutex(ScreenLock);
		fwprintf_s(stderr, L"Winsock initialization error, error code is %d.\n", ErrorCode);
		ScreenLock.unlock();
		PrintError(LOG_LEVEL_1, LOG_ERROR_NETWORK, L"Winsock initialization error", ErrorCode, nullptr, 0);

		return false;
	}
	else {
		GlobalRunningStatus.Initialization_WinSock = true;
	}

//Read commands.
	std::wstring Commands;
#elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
	std::string Commands;
#endif
	for (size_t Index = 1U;(SSIZE_T)Index < argc;++Index)
	{
		Commands = argv[Index];

	//Flush DNS Cache from user.
		if (Commands == COMMAND_FLUSH_DNS)
		{
		#if defined(PLATFORM_WIN)
			FlushDNSMailSlotSender();
		#elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
			FlushDNSFIFOSender();
		#endif

			return false;
		}
	//Windows Firewall Test in first start.
	#if defined(PLATFORM_WIN)
		else if (Commands == COMMAND_FIREWALL_TEST)
		{
			if (!FirewallTest(AF_INET6) && !FirewallTest(AF_INET))
			{
				auto ErrorCode = WSAGetLastError();
				std::unique_lock<std::mutex> ScreenMutex(ScreenLock);
				fwprintf_s(stderr, L"Windows Firewall Test error, error code is %d.\n", ErrorCode);
				ScreenMutex.unlock();
				PrintError(LOG_LEVEL_2, LOG_ERROR_NETWORK, L"Windows Firewall Test error", ErrorCode, nullptr, 0);
			}

			return false;
		}
	#endif
	//Set system daemon.
	#if defined(PLATFORM_LINUX)
		else if (Commands == COMMAND_DISABLE_DAEMON)
		{
			GlobalRunningStatus.Daemon = false;
		}
	#endif
	//Print current version.
		else if (Commands == COMMAND_LONG_PRINT_VERSION || Commands == COMMAND_SHORT_PRINT_VERSION)
		{
			std::unique_lock<std::mutex> ScreenMutex(ScreenLock);
			fwprintf_s(stderr, L"Pcap_DNSProxy ");
			fwprintf_s(stderr, FULL_VERSION);
			fwprintf_s(stderr, L"\n");

			return false;
		}
	//Print library version.
		else if (Commands == COMMAND_LIB_VERSION)
		{
			std::unique_lock<std::mutex> ScreenMutex(ScreenLock);

		#if (defined(ENABLE_LIBSODIUM) || defined(ENABLE_PCAP))
			std::wstring LibVersion;

			//LibSodium version
			#if defined(ENABLE_LIBSODIUM)
				if (MBSToWCSString(SODIUM_VERSION_STRING, strlen(SODIUM_VERSION_STRING), LibVersion))
					fwprintf_s(stderr, L"LibSodium version %ls\n", LibVersion.c_str());
			#endif

			//WinPcap or LibPcap version
			#if defined(ENABLE_PCAP)
				if (MBSToWCSString(pcap_lib_version(), strlen(pcap_lib_version()), LibVersion))
					fwprintf_s(stderr, L"%ls\n", LibVersion.c_str());
			#endif
		#else
			fwprintf(stderr, L"No any available libraries.\n");
		#endif

			return false;
		}
	//Print help messages.
		else if (Commands == COMMAND_LONG_HELP || Commands == COMMAND_SHORT_HELP)
		{
			std::unique_lock<std::mutex> ScreenMutex(ScreenLock);

			fwprintf_s(stderr, L"Pcap_DNSProxy ");
			fwprintf_s(stderr, FULL_VERSION);
		#if defined(PLATFORM_WIN)
			fwprintf_s(stderr, L"(Windows)\n");
		#elif defined(PLATFORM_OPENWRT)
			fwprintf(stderr, L"(OpenWrt)\n");
		#elif defined(PLATFORM_LINUX)
			fwprintf(stderr, L"(Linux)\n");
		#elif defined(PLATFORM_MACX)
			fwprintf(stderr, L"(Mac)\n");
		#endif
			fwprintf_s(stderr, COPYRIGHT_MESSAGE);
			fwprintf_s(stderr, L"\nUsage: Please visit ReadMe... files in Documents folder.\n");
			fwprintf_s(stderr, L"   -v/--version:          Print current version on screen.\n");
			fwprintf_s(stderr, L"   --lib-version:         Print current version of libraries on screen.\n");
			fwprintf_s(stderr, L"   -h/--help:             Print help messages on screen.\n");
			fwprintf_s(stderr, L"   --flush-dns:           Flush all DNS cache in program and system immediately.\n");
		#if defined(PLATFORM_WIN)
			fwprintf_s(stderr, L"   --first-setup:         Test local firewall.\n");
		#endif
			fwprintf_s(stderr, L"   -c/--config-file Path: Set path of configuration file.\n");
		#if defined(PLATFORM_LINUX)
			fwprintf(stderr, L"   --disable-daemon:      Disable daemon mode.\n");
		#endif

			return false;
		}
	//Set working directory from commands.
		else if (Commands == COMMAND_LONG_SET_PATH || Commands == COMMAND_SHORT_SET_PATH)
		{
		//Commands check
			if ((SSIZE_T)Index + 1 >= argc)
			{
				std::unique_lock<std::mutex> ScreenMutex(ScreenLock);
				fwprintf(stderr, L"Commands error.\n");
				ScreenMutex.unlock();
				PrintError(LOG_LEVEL_1, LOG_ERROR_SYSTEM, L"Commands error", 0, nullptr, 0);

				return false;
			}
			else {
				++Index;
				Commands = argv[Index];

			//Path check.
				if (Commands.length() > MAX_PATH)
				{
					std::unique_lock<std::mutex> ScreenMutex(ScreenLock);
					fwprintf_s(stderr, L"Commands error.\n");
					ScreenLock.unlock();
					PrintError(LOG_LEVEL_1, LOG_ERROR_SYSTEM, L"Commands error", 0, nullptr, 0);

					return false;
				}
				else {
					if (!FileNameInit(Commands.c_str()))
						return false;
				}
			}
		}
	}

//Set system daemon.
#if defined(PLATFORM_LINUX)
	if (GlobalRunningStatus.Daemon && daemon(0, 0) == RETURN_ERROR)
	{
		PrintError(LOG_LEVEL_2, LOG_ERROR_SYSTEM, L"Set system daemon error", 0, nullptr, 0);
		return false;
	}
#endif

	return true;
}

//Get path of program from the main function parameter and Winsock initialization
#if defined(PLATFORM_WIN)
bool __fastcall FileNameInit(
	const wchar_t *OriginalPath)
#elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
bool FileNameInit(
	const char *OriginalPath)
#endif
{
//Path process
#if defined(PLATFORM_WIN)
	GlobalRunningStatus.Path_Global->clear();
	GlobalRunningStatus.Path_Global->push_back(OriginalPath);
	GlobalRunningStatus.Path_Global->front().erase(GlobalRunningStatus.Path_Global->front().rfind(L"\\") + 1U);
	for (size_t Index = 0;Index < GlobalRunningStatus.Path_Global->front().length();++Index)
	{
		if ((GlobalRunningStatus.Path_Global->front()).at(Index) == L'\\')
		{
			GlobalRunningStatus.Path_Global->front().insert(Index, L"\\");
			++Index;
		}
	}
#elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
	GlobalRunningStatus.sPath_Global->clear();
	GlobalRunningStatus.sPath_Global->push_back(OriginalPath);
	GlobalRunningStatus.sPath_Global->front().append("/");
	std::wstring StringTemp;
	if (!MBSToWCSString(OriginalPath, PATH_MAX + 1U, StringTemp))
		return false;
	StringTemp.append(L"/");
	GlobalRunningStatus.Path_Global->clear();
	GlobalRunningStatus.Path_Global->push_back(StringTemp);
	StringTemp.clear();
#endif

//Get path of error/running status log file and mark start time.
	GlobalRunningStatus.Path_ErrorLog->clear();
	*GlobalRunningStatus.Path_ErrorLog = GlobalRunningStatus.Path_Global->front();
	GlobalRunningStatus.Path_ErrorLog->append(L"Error.log");
#if (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
	GlobalRunningStatus.sPath_ErrorLog->clear();
	*GlobalRunningStatus.sPath_ErrorLog = GlobalRunningStatus.sPath_Global->front();
	GlobalRunningStatus.sPath_ErrorLog->append("Error.log");
#endif
	Parameter.PrintLogLevel = DEFAULT_LOG_LEVEL;
	GlobalRunningStatus.StartupTime = time(nullptr);

	return true;
}
Ejemplo n.º 8
0
//Print to screen and write to file
bool __fastcall PrintScreenAndWriteFile(
	_In_ const std::wstring Message, 
	_In_opt_ const SSIZE_T ErrorCode, 
	_In_opt_ const size_t Line)
{
//Get current date and time.
	auto TimeStructure = std::make_shared<tm>();
	memset(TimeStructure.get(), 0, sizeof(tm));
	auto TimeValues = time(nullptr);
#if defined(PLATFORM_WIN)
	if (localtime_s(TimeStructure.get(), &TimeValues) > 0)
#elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
	if (localtime_r(&TimeValues, TimeStructure.get()) == nullptr)
#endif
		return false;

//Print startup time at first printing.
	time_t LogStartupTime = 0;
	if (GlobalRunningStatus.StartupTime > 0)
	{
		LogStartupTime = GlobalRunningStatus.StartupTime;
		GlobalRunningStatus.StartupTime = 0;
	}

//Print to screen.
#if defined(PLATFORM_WIN)
	if (GlobalRunningStatus.Console)
#elif defined(PLATFORM_LINUX)
	if (!GlobalRunningStatus.Daemon)
#endif
	{
		std::unique_lock<std::mutex> ScreenMutex(ScreenLock);

	//Print startup time.
		if (LogStartupTime > 0)
		{
			fwprintf_s(stderr, L"%d-%02d-%02d %02d:%02d:%02d -> Log opened at this moment.\n", 
				TimeStructure->tm_year + 1900, 
				TimeStructure->tm_mon + 1, 
				TimeStructure->tm_mday, 
				TimeStructure->tm_hour, 
				TimeStructure->tm_min, 
				TimeStructure->tm_sec);
		}

	//Print message.
		fwprintf_s(stderr, L"%d-%02d-%02d %02d:%02d:%02d -> ", 
			TimeStructure->tm_year + 1900, 
			TimeStructure->tm_mon + 1, 
			TimeStructure->tm_mday, 
			TimeStructure->tm_hour, 
			TimeStructure->tm_min, 
			TimeStructure->tm_sec);
		if (Line > 0 && ErrorCode > 0)
			fwprintf_s(stderr, Message.c_str(), Line, ErrorCode);
		else if (Line > 0)
			fwprintf_s(stderr, Message.c_str(), Line);
		else if (ErrorCode > 0)
			fwprintf_s(stderr, Message.c_str(), ErrorCode);
		else 
			fwprintf_s(stderr, Message.c_str());
	}

//Check whole file size.
	std::unique_lock<std::mutex> ErrorLogMutex(ErrorLogLock);

#if defined(PLATFORM_WIN)
	auto File_WIN32_FILE_ATTRIBUTE_DATA = std::make_shared<WIN32_FILE_ATTRIBUTE_DATA>();
	memset(File_WIN32_FILE_ATTRIBUTE_DATA.get(), 0, sizeof(WIN32_FILE_ATTRIBUTE_DATA));
	if (GetFileAttributesExW(GlobalRunningStatus.Path_ErrorLog->c_str(), GetFileExInfoStandard, File_WIN32_FILE_ATTRIBUTE_DATA.get()) != FALSE)
	{
		auto ErrorFileSize = std::make_shared<LARGE_INTEGER>();
		memset(ErrorFileSize.get(), 0, sizeof(LARGE_INTEGER));
		ErrorFileSize->HighPart = File_WIN32_FILE_ATTRIBUTE_DATA->nFileSizeHigh;
		ErrorFileSize->LowPart = File_WIN32_FILE_ATTRIBUTE_DATA->nFileSizeLow;
		if (ErrorFileSize->QuadPart > 0 && (size_t)ErrorFileSize->QuadPart >= Parameter.LogMaxSize)
		{
			if (DeleteFileW(GlobalRunningStatus.Path_ErrorLog->c_str()) != FALSE)
			{
				ErrorLogMutex.unlock();
				PrintError(LOG_ERROR_SYSTEM, L"Old error log file was deleted", 0, nullptr, 0);
				ErrorLogMutex.lock();
			}
			else {
				return false;
			}
		}
	}

	File_WIN32_FILE_ATTRIBUTE_DATA.reset();
#elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
	auto FileStat = std::make_shared<struct stat>();
	memset(FileStat.get(), 0, sizeof(struct stat));
	if (stat(GlobalRunningStatus.sPath_ErrorLog->c_str(), FileStat.get()) == 0 && FileStat->st_size >= (off_t)Parameter.LogMaxSize)
	{
		if (remove(GlobalRunningStatus.sPath_ErrorLog->c_str()) == 0)
		{
			ErrorLogMutex.unlock();
			PrintError(LOG_ERROR_SYSTEM, L"Old error log file was deleted", 0, nullptr, 0);
			ErrorLogMutex.lock();
		}
		else {
			return false;
		}
	}

	FileStat.reset();
#endif

//Write to file.
#if defined(PLATFORM_WIN)
	FILE *Output = nullptr;
	if (_wfopen_s(&Output, GlobalRunningStatus.Path_ErrorLog->c_str(), L"a,ccs=UTF-8") == 0 && Output != nullptr)
#elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
	auto Output = fopen(GlobalRunningStatus.sPath_ErrorLog->c_str(), "a");
	if (Output != nullptr)
#endif
	{
	//Print startup time.
		if (LogStartupTime > 0)
		{
			fwprintf_s(Output, L"%d-%02d-%02d %02d:%02d:%02d -> Log opened at this moment.\n", 
				TimeStructure->tm_year + 1900, 
				TimeStructure->tm_mon + 1, 
				TimeStructure->tm_mday, 
				TimeStructure->tm_hour, 
				TimeStructure->tm_min, 
				TimeStructure->tm_sec);
		}

	//Print message.
		fwprintf_s(Output, L"%d-%02d-%02d %02d:%02d:%02d -> ", 
			TimeStructure->tm_year + 1900, 
			TimeStructure->tm_mon + 1, 
			TimeStructure->tm_mday, 
			TimeStructure->tm_hour, 
			TimeStructure->tm_min, 
			TimeStructure->tm_sec);
		if (Line > 0 && ErrorCode > 0)
			fwprintf_s(Output, Message.c_str(), Line, ErrorCode);
		else if (Line > 0)
			fwprintf_s(Output, Message.c_str(), Line);
		else if (ErrorCode > 0)
			fwprintf_s(Output, Message.c_str(), ErrorCode);
		else 
			fwprintf_s(Output, Message.c_str());

		fclose(Output);
	}
	else {
		return false;
	}

	return true;
}