SocketValueTable::~SocketValueTable(
	void)
{
//Close all sockets.
	for (auto &SocketItem:ValueSet)
		SocketSetting(SocketItem.Socket, SOCKET_SETTING_TYPE::CLOSE, false, nullptr);

	return;
}

#if defined(ENABLE_PCAP)
EventTable_SocketSend::EventTable_SocketSend(
	void)
{
	Protocol = 0;
	memset(&SocketTimeout, 0, sizeof(SocketTimeout));
	memset(&IntervalTimeout, 0, sizeof(IntervalTimeout));
	EventBase = nullptr;
	EventList = nullptr;
	SocketValue = nullptr;
	SendBuffer = nullptr;
	RecvBuffer = nullptr;
	SendSize = 0;
	RecvSize = 0;
	TotalSleepTime = 0;
	OnceTimes = 0;
	RetestTimes = 0;
	FileModifiedTime = 0;
	PacketSequence = 0;

	return;
}

//EventTable_SocketSend class destructor
EventTable_SocketSend::~EventTable_SocketSend(
	void)
{
//Free all event items.
	for (auto &EventItem:*EventList)
	{
		if (EventItem != nullptr)
		{
			event_free(EventItem);
			EventItem = nullptr;
		}
	}

//Free event base.
	if (EventBase != nullptr)
	{
		event_base_free(EventBase);
		EventBase = nullptr;
	}

	return;
}

EventTable_TransmissionOnce::EventTable_TransmissionOnce(
	void)
{
	Protocol_Network = 0;
	Protocol_Transport = nullptr;
	SocketTimeout = nullptr;
	memset(&IntervalTimeout, 0, sizeof(IntervalTimeout));
	EventBase = nullptr;
	EventList = nullptr;
	EventBufferList = nullptr;
	SocketValue = nullptr;
	SendBuffer = nullptr;
	RecvBuffer = nullptr;
	SendSize = 0;
	SendLen = nullptr;
	SendTimes = nullptr;
	RecvSize = 0;
	TotalSleepTime = 0;
	OnceTimes = 0;
	RetestTimes = 0;
	FileModifiedTime = 0;

	return;
}

//EventTable_TransmissionOnce class destructor
EventTable_TransmissionOnce::~EventTable_TransmissionOnce(
	void)
{
//Free all bufferevent items.
	for (auto &EventBufferItem:*EventBufferList)
	{
		if (EventBufferItem != nullptr)
		{
			bufferevent_free(EventBufferItem);
			EventBufferItem = nullptr;
		}
	}

//Free all event items.
	for (auto &EventItem:*EventList)
	{
		if (EventItem != nullptr)
		{
			event_free(EventItem);
			EventItem = nullptr;
		}
	}

//Free event base.
	if (EventBase != nullptr)
	{
		event_base_free(EventBase);
		EventBase = nullptr;
	}

	return;
}
#endif

SocketSelectingOnceTable::SocketSelectingOnceTable(
	void)
{
	RecvLen = 0;
	IsPacketDone = false;

	return;
}

#if defined(ENABLE_PCAP)
CaptureDeviceTable::CaptureDeviceTable(
	void)
{
	memset(this, 0, sizeof(CAPTURE_DEVICE_TABLE));
	try {
		DeviceName = new std::string();
	}
	catch (std::bad_alloc &)
	{
		delete DeviceName;
		DeviceName = nullptr;

	//Exit process.
		exit(EXIT_FAILURE);
	}

	return;
}

//CaptureDeviceTable class destructor
CaptureDeviceTable::~CaptureDeviceTable(
	void)
{
	delete DeviceName;
	DeviceName = nullptr;
	if (DeviceHandle != nullptr)
	{
		pcap_close(DeviceHandle);
		DeviceHandle = nullptr;
	}
	if (!CheckEmptyBuffer(&BPF_Code, sizeof(BPF_Code)))
	{
		pcap_freecode(&BPF_Code);
		memset(&BPF_Code, 0, sizeof(BPF_Code));
	}

	return;
}

OutputPacketTable::OutputPacketTable(
	void)
{
//Initialization
	memset(&SocketData_Input, 0, sizeof(SocketData_Input));
	SocketData_Input.Socket = INVALID_SOCKET;
	ReceiveIndex = 0;
	Protocol_Network = 0;
	Protocol_Transport = 0;
	ClearPortTime = 0;

	return;
}
#endif

#if defined(ENABLE_LIBSODIUM)
DNSCurveConfigurationTable::DNSCurveConfigurationTable(
	void)
{
//Class constructor
	memset(this, 0, sizeof(DNSCURVE_CONFIGURATION_TABLE));
	try {
	//[DNSCurve Database] block
		DatabaseName = new std::wstring();
	#if (defined(PLATFORM_FREEBSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS))
		DatabaseName_MBS = new std::string();
	#endif
		Database_Target_Server_Main_IPv6 = new std::string();
		Database_Target_Server_Alternate_IPv6 = new std::string();
		Database_Target_Server_Main_IPv4 = new std::string();
		Database_Target_Server_Alternate_IPv4 = new std::string();
		Database_LineData = new std::vector<std::vector<std::string>>();

	//[DNSCurve Addresses] block
		DNSCurve_Target_Server_Main_IPv6.ProviderName = new uint8_t[DOMAIN_MAXSIZE]();
		DNSCurve_Target_Server_Alternate_IPv6.ProviderName = new uint8_t[DOMAIN_MAXSIZE]();
		DNSCurve_Target_Server_Main_IPv4.ProviderName = new uint8_t[DOMAIN_MAXSIZE]();
		DNSCurve_Target_Server_Alternate_IPv4.ProviderName = new uint8_t[DOMAIN_MAXSIZE]();

	//[DNSCurve Keys] block
		Client_PublicKey = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		Client_SecretKey = reinterpret_cast<uint8_t *>(sodium_malloc(crypto_box_SECRETKEYBYTES));
		DNSCurve_Target_Server_Main_IPv6.PrecomputationKey = reinterpret_cast<uint8_t *>(sodium_malloc(crypto_box_BEFORENMBYTES));
		DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey = reinterpret_cast<uint8_t *>(sodium_malloc(crypto_box_BEFORENMBYTES));
		DNSCurve_Target_Server_Main_IPv4.PrecomputationKey = reinterpret_cast<uint8_t *>(sodium_malloc(crypto_box_BEFORENMBYTES));
		DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey = reinterpret_cast<uint8_t *>(sodium_malloc(crypto_box_BEFORENMBYTES));
		DNSCurve_Target_Server_Main_IPv6.ServerPublicKey = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		DNSCurve_Target_Server_Main_IPv4.ServerPublicKey = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		DNSCurve_Target_Server_Main_IPv6.ServerFingerprint = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		DNSCurve_Target_Server_Main_IPv4.ServerFingerprint = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint = new uint8_t[crypto_box_PUBLICKEYBYTES]();

	//[DNSCurve Magic Number] block
		DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
		DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
		DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
		DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
		DNSCurve_Target_Server_Main_IPv4.SendMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
		DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
		DNSCurve_Target_Server_Main_IPv6.SendMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
		DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
	}
	catch (std::bad_alloc &)
	{
	//[DNSCurve Database] block
		delete DatabaseName;
		DatabaseName = nullptr;
	#if (defined(PLATFORM_FREEBSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS))
		delete DatabaseName_MBS;
		DatabaseName_MBS = nullptr;
	#endif
		delete Database_Target_Server_Main_IPv6;
		delete Database_Target_Server_Alternate_IPv6;
		delete Database_Target_Server_Main_IPv4;
		delete Database_Target_Server_Alternate_IPv4;
		delete Database_LineData;
		Database_Target_Server_Main_IPv6 = nullptr;
		Database_Target_Server_Alternate_IPv6 = nullptr;
		Database_Target_Server_Main_IPv4 = nullptr;
		Database_Target_Server_Alternate_IPv4 = nullptr;
		Database_LineData = nullptr;

	//[DNSCurve Addresses] block
		delete[] DNSCurve_Target_Server_Main_IPv6.ProviderName;
		delete[] DNSCurve_Target_Server_Alternate_IPv6.ProviderName;
		delete[] DNSCurve_Target_Server_Main_IPv4.ProviderName;
		delete[] DNSCurve_Target_Server_Alternate_IPv4.ProviderName;
		DNSCurve_Target_Server_Main_IPv6.ProviderName = nullptr;
		DNSCurve_Target_Server_Alternate_IPv6.ProviderName = nullptr;
		DNSCurve_Target_Server_Main_IPv4.ProviderName = nullptr;
		DNSCurve_Target_Server_Alternate_IPv4.ProviderName = nullptr;

	//[DNSCurve Keys] block
		delete[] Client_PublicKey;
		sodium_free(Client_SecretKey);
		sodium_free(DNSCurve_Target_Server_Main_IPv6.PrecomputationKey);
		sodium_free(DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey);
		sodium_free(DNSCurve_Target_Server_Main_IPv4.PrecomputationKey);
		sodium_free(DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey);
		delete[] DNSCurve_Target_Server_Main_IPv6.ServerPublicKey;
		delete[] DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey;
		delete[] DNSCurve_Target_Server_Main_IPv4.ServerPublicKey;
		delete[] DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey;
		delete[] DNSCurve_Target_Server_Main_IPv6.ServerFingerprint;
		delete[] DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint;
		delete[] DNSCurve_Target_Server_Main_IPv4.ServerFingerprint;
		delete[] DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint;
		Client_PublicKey = nullptr;
		Client_SecretKey = nullptr;
		DNSCurve_Target_Server_Main_IPv6.PrecomputationKey = nullptr;
		DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey = nullptr;
		DNSCurve_Target_Server_Main_IPv4.PrecomputationKey = nullptr;
		DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey = nullptr;
		DNSCurve_Target_Server_Main_IPv6.ServerPublicKey = nullptr;
		DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey = nullptr;
		DNSCurve_Target_Server_Main_IPv4.ServerPublicKey = nullptr;
		DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey = nullptr;
		DNSCurve_Target_Server_Main_IPv6.ServerFingerprint = nullptr;
		DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint = nullptr;
		DNSCurve_Target_Server_Main_IPv4.ServerFingerprint = nullptr;
		DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint = nullptr;

	//[DNSCurve Magic Number] block
		delete[] DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber;
		delete[] DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber;
		delete[] DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber;
		delete[] DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber;
		delete[] DNSCurve_Target_Server_Main_IPv6.SendMagicNumber;
		delete[] DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber;
		delete[] DNSCurve_Target_Server_Main_IPv4.SendMagicNumber;
		delete[] DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber;
		DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber = nullptr;
		DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber = nullptr;
		DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber = nullptr;
		DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber = nullptr;
		DNSCurve_Target_Server_Main_IPv6.SendMagicNumber = nullptr;
		DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber = nullptr;
		DNSCurve_Target_Server_Main_IPv4.SendMagicNumber = nullptr;
		DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber = nullptr;

	//Exit process.
		exit(EXIT_FAILURE);
	}

//DNSCurveConfigurationTable settings
	DNSCurveConfigurationTableSetting(this);
	return;
}

//DNSCurveConfigurationTable class constructor settings
void DNSCurveConfigurationTableSetting(
	DNSCURVE_CONFIGURATION_TABLE * const DNSCurveConfigurationParameter)
{
//[DNSCurve Addresses] block
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ProviderName, 0, DOMAIN_MAXSIZE);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ProviderName, 0, DOMAIN_MAXSIZE);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ProviderName, 0, DOMAIN_MAXSIZE);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ProviderName, 0, DOMAIN_MAXSIZE);

//[DNSCurve Keys] block
	memset(DNSCurveConfigurationParameter->Client_PublicKey, 0, crypto_box_PUBLICKEYBYTES);
	sodium_memzero(DNSCurveConfigurationParameter->Client_SecretKey, crypto_box_SECRETKEYBYTES);
	sodium_memzero(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES);
	sodium_memzero(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES);
	sodium_memzero(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES);
	sodium_memzero(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);

//[DNSCurve Magic Number] block
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);

//Default settings
	DNSCurveConfigurationParameter->DNSCurveProtocol_Network = REQUEST_MODE_NETWORK::BOTH;
	DNSCurveConfigurationParameter->DNSCurveProtocol_Transport = REQUEST_MODE_TRANSPORT::UDP;
	DNSCurveConfigurationParameter->DNSCurvePayloadSize = EDNS_PACKET_MINSIZE;
#if defined(PLATFORM_WIN)
	DNSCurveConfigurationParameter->DNSCurve_SocketTimeout_Reliable = DNSCURVE_DEFAULT_RELIABLE_SOCKET_TIMEOUT;
	DNSCurveConfigurationParameter->DNSCurve_SocketTimeout_Unreliable = DNSCURVE_DEFAULT_UNRELIABLE_SOCKET_TIMEOUT;
#elif (defined(PLATFORM_FREEBSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS))
	DNSCurveConfigurationParameter->DNSCurve_SocketTimeout_Reliable.tv_sec = DNSCURVE_DEFAULT_RELIABLE_SOCKET_TIMEOUT;
	DNSCurveConfigurationParameter->DNSCurve_SocketTimeout_Unreliable.tv_sec = DNSCURVE_DEFAULT_UNRELIABLE_SOCKET_TIMEOUT;
#endif
	DNSCurveConfigurationParameter->KeyRecheckTime = DNSCURVE_DEFAULT_RECHECK_TIME * SECOND_TO_MILLISECOND;

	return;
}

//DNSCurveConfigurationTable class destructor
DNSCurveConfigurationTable::~DNSCurveConfigurationTable(
	void)
{
//[DNSCurve Database] block
	delete DatabaseName;
	DatabaseName = nullptr;
#if (defined(PLATFORM_FREEBSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS))
	delete DatabaseName_MBS;
	DatabaseName_MBS = nullptr;
#endif
	delete Database_Target_Server_Main_IPv6;
	delete Database_Target_Server_Alternate_IPv6;
	delete Database_Target_Server_Main_IPv4;
	delete Database_Target_Server_Alternate_IPv4;
	delete Database_LineData;
	Database_Target_Server_Main_IPv6 = nullptr;
	Database_Target_Server_Alternate_IPv6 = nullptr;
	Database_Target_Server_Main_IPv4 = nullptr;
	Database_Target_Server_Alternate_IPv4 = nullptr;
	Database_LineData = nullptr;

//[DNSCurve Addresses] block
	delete[] DNSCurve_Target_Server_Main_IPv6.ProviderName;
	delete[] DNSCurve_Target_Server_Alternate_IPv6.ProviderName;
	delete[] DNSCurve_Target_Server_Main_IPv4.ProviderName;
	delete[] DNSCurve_Target_Server_Alternate_IPv4.ProviderName;
	DNSCurve_Target_Server_Main_IPv6.ProviderName = nullptr;
	DNSCurve_Target_Server_Alternate_IPv6.ProviderName = nullptr;
	DNSCurve_Target_Server_Main_IPv4.ProviderName = nullptr;
	DNSCurve_Target_Server_Alternate_IPv4.ProviderName = nullptr;

//[DNSCurve Keys] block
	delete[] Client_PublicKey;
	sodium_free(Client_SecretKey);
	sodium_free(DNSCurve_Target_Server_Main_IPv6.PrecomputationKey);
	sodium_free(DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey);
	sodium_free(DNSCurve_Target_Server_Main_IPv4.PrecomputationKey);
	sodium_free(DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey);
	delete[] DNSCurve_Target_Server_Main_IPv6.ServerPublicKey;
	delete[] DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey;
	delete[] DNSCurve_Target_Server_Main_IPv4.ServerPublicKey;
	delete[] DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey;
	delete[] DNSCurve_Target_Server_Main_IPv6.ServerFingerprint;
	delete[] DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint;
	delete[] DNSCurve_Target_Server_Main_IPv4.ServerFingerprint;
	delete[] DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint;
	Client_PublicKey = nullptr;
	Client_SecretKey = nullptr;
	DNSCurve_Target_Server_Main_IPv6.PrecomputationKey = nullptr;
	DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey = nullptr;
	DNSCurve_Target_Server_Main_IPv4.PrecomputationKey = nullptr;
	DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey = nullptr;
	DNSCurve_Target_Server_Main_IPv6.ServerPublicKey = nullptr;
	DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey = nullptr;
	DNSCurve_Target_Server_Main_IPv4.ServerPublicKey = nullptr;
	DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey = nullptr;
	DNSCurve_Target_Server_Main_IPv6.ServerFingerprint = nullptr;
	DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint = nullptr;
	DNSCurve_Target_Server_Main_IPv4.ServerFingerprint = nullptr;
	DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint = nullptr;

//[DNSCurve Magic Number] block
	delete[] DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber;
	delete[] DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber;
	delete[] DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber;
	delete[] DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber;
	delete[] DNSCurve_Target_Server_Main_IPv6.SendMagicNumber;
	delete[] DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber;
	delete[] DNSCurve_Target_Server_Main_IPv4.SendMagicNumber;
	delete[] DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber;
	DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber = nullptr;
	DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber = nullptr;
	DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber = nullptr;
	DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber = nullptr;
	DNSCurve_Target_Server_Main_IPv6.SendMagicNumber = nullptr;
	DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber = nullptr;
	DNSCurve_Target_Server_Main_IPv4.SendMagicNumber = nullptr;
	DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber = nullptr;

	return;
}

//DNSCurveConfigurationTable class SetToMonitorItem function
void DNSCurveConfigurationTable::SetToMonitorItem(
	void)
{
//Delete and reset pointers.
	delete DatabaseName;
	DatabaseName = nullptr;
#if (defined(PLATFORM_FREEBSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS))
	delete DatabaseName_MBS;
	DatabaseName_MBS = nullptr;
#endif
	delete Database_Target_Server_Main_IPv6;
	delete Database_Target_Server_Alternate_IPv6;
	delete Database_Target_Server_Main_IPv4;
	delete Database_Target_Server_Alternate_IPv4;
	Database_Target_Server_Main_IPv6 = nullptr;
	Database_Target_Server_Alternate_IPv6 = nullptr;
	Database_Target_Server_Main_IPv4 = nullptr;
	Database_Target_Server_Alternate_IPv4 = nullptr;
	delete[] DNSCurve_Target_Server_Main_IPv6.ProviderName;
	delete[] DNSCurve_Target_Server_Alternate_IPv6.ProviderName;
	delete[] DNSCurve_Target_Server_Main_IPv4.ProviderName;
	delete[] DNSCurve_Target_Server_Alternate_IPv4.ProviderName;
	DNSCurve_Target_Server_Main_IPv6.ProviderName = nullptr;
	DNSCurve_Target_Server_Alternate_IPv6.ProviderName = nullptr;
	DNSCurve_Target_Server_Main_IPv4.ProviderName = nullptr;
	DNSCurve_Target_Server_Alternate_IPv4.ProviderName = nullptr;

	return;
}

//DNSCurveConfigurationTable class MonitorItemToUsing function
void DNSCurveConfigurationTable::MonitorItemToUsing(
	DNSCurveConfigurationTable * const DNSCurveConfigurationParameter)
{
	DNSCurveConfigurationParameter->DNSCurve_SocketTimeout_Reliable = DNSCurve_SocketTimeout_Reliable;
	DNSCurveConfigurationParameter->DNSCurve_SocketTimeout_Unreliable = DNSCurve_SocketTimeout_Unreliable;
	DNSCurveConfigurationParameter->KeyRecheckTime = KeyRecheckTime;

//[DNSCurve Keys] block
	if (DNSCurveConfigurationParameter->Client_PublicKey != nullptr && !CheckEmptyBuffer(Client_PublicKey, crypto_box_PUBLICKEYBYTES) &&
		memcmp(DNSCurveConfigurationParameter->Client_PublicKey, Client_PublicKey, crypto_box_PUBLICKEYBYTES) != 0)
			memcpy_s(DNSCurveConfigurationParameter->Client_PublicKey, crypto_box_PUBLICKEYBYTES, Client_PublicKey, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->Client_SecretKey != nullptr && sodium_is_zero(Client_SecretKey, crypto_box_PUBLICKEYBYTES) == 0 &&
		sodium_memcmp(DNSCurveConfigurationParameter->Client_SecretKey, Client_SecretKey, crypto_box_PUBLICKEYBYTES) != 0)
			memcpy_s(DNSCurveConfigurationParameter->Client_SecretKey, crypto_box_PUBLICKEYBYTES, Client_SecretKey, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.PrecomputationKey != nullptr &&
		sodium_is_zero(DNSCurve_Target_Server_Main_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES) == 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES, DNSCurve_Target_Server_Main_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey != nullptr &&
		sodium_is_zero(DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES) == 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES, DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.PrecomputationKey != nullptr &&
		sodium_is_zero(DNSCurve_Target_Server_Main_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES) == 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES, DNSCurve_Target_Server_Main_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey != nullptr &&
		sodium_is_zero(DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES) == 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES, DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ServerPublicKey != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES) &&
		memcmp(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ServerPublicKey, DNSCurve_Target_Server_Main_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES) != 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Main_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES) &&
		memcmp(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey, DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES) != 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ServerPublicKey != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES) &&
		memcmp(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ServerPublicKey, DNSCurve_Target_Server_Main_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES) != 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Main_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES) &&
		memcmp(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey, DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES) != 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ServerFingerprint != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv6.ServerFingerprint, crypto_box_PUBLICKEYBYTES))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ServerFingerprint, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Main_IPv6.ServerFingerprint, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint, crypto_box_PUBLICKEYBYTES))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ServerFingerprint != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv4.ServerFingerprint, crypto_box_PUBLICKEYBYTES))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ServerFingerprint, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Main_IPv4.ServerFingerprint, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint, crypto_box_PUBLICKEYBYTES))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint, crypto_box_PUBLICKEYBYTES);

//[DNSCurve Magic Number] block
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.SendMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv6.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Main_IPv6.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.SendMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv4.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Main_IPv4.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);

	return;
}

//DNSCurveConfigurationTable class MonitorItemReset function
void DNSCurveConfigurationTable::MonitorItemReset(
	void)
{
#if defined(PLATFORM_WIN)
	DNSCurve_SocketTimeout_Reliable = DNSCURVE_DEFAULT_RELIABLE_SOCKET_TIMEOUT;
	DNSCurve_SocketTimeout_Unreliable = DNSCURVE_DEFAULT_UNRELIABLE_SOCKET_TIMEOUT;
#elif (defined(PLATFORM_FREEBSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS))
	DNSCurve_SocketTimeout_Reliable.tv_sec = DNSCURVE_DEFAULT_RELIABLE_SOCKET_TIMEOUT;
	DNSCurve_SocketTimeout_Reliable.tv_usec = 0;
	DNSCurve_SocketTimeout_Unreliable.tv_sec = DNSCURVE_DEFAULT_UNRELIABLE_SOCKET_TIMEOUT;
	DNSCurve_SocketTimeout_Unreliable.tv_usec = 0;
#endif
	KeyRecheckTime = DNSCURVE_DEFAULT_RECHECK_TIME * SECOND_TO_MILLISECOND;

//[DNSCurve database] block
	if (Database_LineData != nullptr)
	{
		Database_LineData->clear();
		Database_LineData->shrink_to_fit();
	}

//[DNSCurve Keys] block
	if (Client_PublicKey != nullptr)
		memset(Client_PublicKey, 0, crypto_box_PUBLICKEYBYTES);
	if (Client_SecretKey != nullptr)
		sodium_memzero(Client_SecretKey, crypto_box_SECRETKEYBYTES);
	if (DNSCurve_Target_Server_Main_IPv6.PrecomputationKey != nullptr)
		sodium_memzero(DNSCurve_Target_Server_Main_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey != nullptr)
		sodium_memzero(DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurve_Target_Server_Main_IPv4.PrecomputationKey != nullptr)
		sodium_memzero(DNSCurve_Target_Server_Main_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey != nullptr)
		sodium_memzero(DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurve_Target_Server_Main_IPv6.ServerPublicKey != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv6.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	if (DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	if (DNSCurve_Target_Server_Main_IPv4.ServerPublicKey != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv4.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	if (DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	if (DNSCurve_Target_Server_Main_IPv6.ServerFingerprint != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv6.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);
	if (DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);
	if (DNSCurve_Target_Server_Main_IPv4.ServerFingerprint != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv4.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);
	if (DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);

//[DNSCurve Magic Number] block
	if (DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurve_Target_Server_Main_IPv6.SendMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv6.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurve_Target_Server_Main_IPv4.SendMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv4.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);

	return;
}

DNSCurveSocketSelectingTable::DNSCurveSocketSelectingTable(
	void)
{
	ServerType = DNSCURVE_SERVER_TYPE::NONE;
	PrecomputationKey = nullptr;
	ReceiveMagicNumber = nullptr;
	SendBuffer = nullptr;
	SendSize = 0;
	RecvLen = 0;
	IsPacketDone = false;

	return;
}
#endif

#if defined(ENABLE_TLS)
#if defined(PLATFORM_WIN)
SSPIHandleTable::SSPIHandleTable(
	void)
{
	memset(&ClientCredentials, 0, sizeof(ClientCredentials));
	memset(&ContextHandle, 0, sizeof(ContextHandle));
	InputFlags = 0;
	memset(&StreamSizes, 0, sizeof(StreamSizes));
	LastReturnValue = 0;

	return;
}

//SSPIHandleTable class destructor
SSPIHandleTable::~SSPIHandleTable(
	void)
{
	FreeCredentialsHandle(&ClientCredentials);
	DeleteSecurityContext(&ContextHandle);

	return;
}
#elif (defined(PLATFORM_FREEBSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS))
OpenSSLContextTable::OpenSSLContextTable(
	void)
{
	MethodContext = nullptr;
	SessionBIO = nullptr;
	SessionData = nullptr;
	Protocol_Network = 0;
	Protocol_Transport = 0;
	Socket = INVALID_SOCKET;

	return;
}

//OpenSSLContextTable class destructor
OpenSSLContextTable::~OpenSSLContextTable(
	void)
{
//Free all sessions.
	if (SessionBIO != nullptr)
	{
		BIO_free_all(SessionBIO);
		SessionBIO = nullptr;
	}

//Free all method context.
	if (MethodContext != nullptr)
	{
		SSL_CTX_free(MethodContext);
		MethodContext = nullptr;
	}

//Close all sockets.
	if (SocketSetting(Socket, SOCKET_SETTING_TYPE::INVALID_CHECK, false, nullptr))
		SocketSetting(Socket, SOCKET_SETTING_TYPE::CLOSE, false, nullptr);

	return;
}
#endif
#endif


try {
		DeviceName = new std::string();
	}
	catch (std::bad_alloc &)
	{
		delete DeviceName;
		DeviceName = nullptr;

	//Exit process.
		exit(EXIT_FAILURE);
	}

	return;
}

//CaptureDeviceTable class destructor
CaptureDeviceTable::~CaptureDeviceTable(
	void)
{
	delete DeviceName;
	DeviceName = nullptr;
	if (DeviceHandle != nullptr)
	{
		pcap_close(DeviceHandle);
		DeviceHandle = nullptr;
	}
	if (!CheckEmptyBuffer(&BPF_Code, sizeof(BPF_Code)))
	{
		pcap_freecode(&BPF_Code);
		memset(&BPF_Code, 0, sizeof(BPF_Code));
	}

	return;
}

OutputPacketTable::OutputPacketTable(
	void)
{
//Initialization
	memset(&SocketData_Input, 0, sizeof(SocketData_Input));
	SocketData_Input.Socket = INVALID_SOCKET;
	ReceiveIndex = 0;
	Protocol_Network = 0;
	Protocol_Transport = 0;
	ClearPortTime = 0;

	return;
}
#endif

#if defined(ENABLE_LIBSODIUM)
DNSCurveConfigurationTable::DNSCurveConfigurationTable(
	void)
{
//Class constructor
	memset(this, 0, sizeof(DNSCURVE_CONFIGURATION_TABLE));
	try {
	//[DNSCurve Database] block
		DatabaseName = new std::wstring();
	#if (defined(PLATFORM_FREEBSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS))
		DatabaseName_MBS = new std::string();
	#endif
		Database_Target_Server_Main_IPv6 = new std::string();
		Database_Target_Server_Alternate_IPv6 = new std::string();
		Database_Target_Server_Main_IPv4 = new std::string();
		Database_Target_Server_Alternate_IPv4 = new std::string();
		Database_LineData = new std::vector<std::vector<std::string>>();

	//[DNSCurve Addresses] block
		DNSCurve_Target_Server_Main_IPv6.ProviderName = new uint8_t[DOMAIN_MAXSIZE]();
		DNSCurve_Target_Server_Alternate_IPv6.ProviderName = new uint8_t[DOMAIN_MAXSIZE]();
		DNSCurve_Target_Server_Main_IPv4.ProviderName = new uint8_t[DOMAIN_MAXSIZE]();
		DNSCurve_Target_Server_Alternate_IPv4.ProviderName = new uint8_t[DOMAIN_MAXSIZE]();

	//[DNSCurve Keys] block
		Client_PublicKey = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		Client_SecretKey = reinterpret_cast<uint8_t *>(sodium_malloc(crypto_box_SECRETKEYBYTES));
		DNSCurve_Target_Server_Main_IPv6.PrecomputationKey = reinterpret_cast<uint8_t *>(sodium_malloc(crypto_box_BEFORENMBYTES));
		DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey = reinterpret_cast<uint8_t *>(sodium_malloc(crypto_box_BEFORENMBYTES));
		DNSCurve_Target_Server_Main_IPv4.PrecomputationKey = reinterpret_cast<uint8_t *>(sodium_malloc(crypto_box_BEFORENMBYTES));
		DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey = reinterpret_cast<uint8_t *>(sodium_malloc(crypto_box_BEFORENMBYTES));
		DNSCurve_Target_Server_Main_IPv6.ServerPublicKey = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		DNSCurve_Target_Server_Main_IPv4.ServerPublicKey = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		DNSCurve_Target_Server_Main_IPv6.ServerFingerprint = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		DNSCurve_Target_Server_Main_IPv4.ServerFingerprint = new uint8_t[crypto_box_PUBLICKEYBYTES]();
		DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint = new uint8_t[crypto_box_PUBLICKEYBYTES]();

	//[DNSCurve Magic Number] block
		DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
		DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
		DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
		DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
		DNSCurve_Target_Server_Main_IPv4.SendMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
		DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
		DNSCurve_Target_Server_Main_IPv6.SendMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
		DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber = new uint8_t[DNSCURVE_MAGIC_QUERY_LEN]();
	}
	catch (std::bad_alloc &)
	{
	//[DNSCurve Database] block
		delete DatabaseName;
		DatabaseName = nullptr;
	#if (defined(PLATFORM_FREEBSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS))
		delete DatabaseName_MBS;
		DatabaseName_MBS = nullptr;
	#endif
		delete Database_Target_Server_Main_IPv6;
		delete Database_Target_Server_Alternate_IPv6;
		delete Database_Target_Server_Main_IPv4;
		delete Database_Target_Server_Alternate_IPv4;
		delete Database_LineData;
		Database_Target_Server_Main_IPv6 = nullptr;
		Database_Target_Server_Alternate_IPv6 = nullptr;
		Database_Target_Server_Main_IPv4 = nullptr;
		Database_Target_Server_Alternate_IPv4 = nullptr;
		Database_LineData = nullptr;

	//[DNSCurve Addresses] block
		delete[] DNSCurve_Target_Server_Main_IPv6.ProviderName;
		delete[] DNSCurve_Target_Server_Alternate_IPv6.ProviderName;
		delete[] DNSCurve_Target_Server_Main_IPv4.ProviderName;
		delete[] DNSCurve_Target_Server_Alternate_IPv4.ProviderName;
		DNSCurve_Target_Server_Main_IPv6.ProviderName = nullptr;
		DNSCurve_Target_Server_Alternate_IPv6.ProviderName = nullptr;
		DNSCurve_Target_Server_Main_IPv4.ProviderName = nullptr;
		DNSCurve_Target_Server_Alternate_IPv4.ProviderName = nullptr;

	//[DNSCurve Keys] block
		delete[] Client_PublicKey;
		sodium_free(Client_SecretKey);
		sodium_free(DNSCurve_Target_Server_Main_IPv6.PrecomputationKey);
		sodium_free(DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey);
		sodium_free(DNSCurve_Target_Server_Main_IPv4.PrecomputationKey);
		sodium_free(DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey);
		delete[] DNSCurve_Target_Server_Main_IPv6.ServerPublicKey;
		delete[] DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey;
		delete[] DNSCurve_Target_Server_Main_IPv4.ServerPublicKey;
		delete[] DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey;
		delete[] DNSCurve_Target_Server_Main_IPv6.ServerFingerprint;
		delete[] DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint;
		delete[] DNSCurve_Target_Server_Main_IPv4.ServerFingerprint;
		delete[] DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint;
		Client_PublicKey = nullptr;
		Client_SecretKey = nullptr;
		DNSCurve_Target_Server_Main_IPv6.PrecomputationKey = nullptr;
		DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey = nullptr;
		DNSCurve_Target_Server_Main_IPv4.PrecomputationKey = nullptr;
		DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey = nullptr;
		DNSCurve_Target_Server_Main_IPv6.ServerPublicKey = nullptr;
		DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey = nullptr;
		DNSCurve_Target_Server_Main_IPv4.ServerPublicKey = nullptr;
		DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey = nullptr;
		DNSCurve_Target_Server_Main_IPv6.ServerFingerprint = nullptr;
		DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint = nullptr;
		DNSCurve_Target_Server_Main_IPv4.ServerFingerprint = nullptr;
		DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint = nullptr;

	//[DNSCurve Magic Number] block
		delete[] DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber;
		delete[] DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber;
		delete[] DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber;
		delete[] DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber;
		delete[] DNSCurve_Target_Server_Main_IPv6.SendMagicNumber;
		delete[] DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber;
		delete[] DNSCurve_Target_Server_Main_IPv4.SendMagicNumber;
		delete[] DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber;
		DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber = nullptr;
		DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber = nullptr;
		DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber = nullptr;
		DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber = nullptr;
		DNSCurve_Target_Server_Main_IPv6.SendMagicNumber = nullptr;
		DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber = nullptr;
		DNSCurve_Target_Server_Main_IPv4.SendMagicNumber = nullptr;
		DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber = nullptr;

	//Exit process.
		exit(EXIT_FAILURE);
	}

//DNSCurveConfigurationTable settings
	DNSCurveConfigurationTableSetting(this);
	return;
}

//DNSCurveConfigurationTable class constructor settings
void DNSCurveConfigurationTableSetting(
	DNSCURVE_CONFIGURATION_TABLE * const DNSCurveConfigurationParameter)
{
//[DNSCurve Addresses] block
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ProviderName, 0, DOMAIN_MAXSIZE);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ProviderName, 0, DOMAIN_MAXSIZE);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ProviderName, 0, DOMAIN_MAXSIZE);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ProviderName, 0, DOMAIN_MAXSIZE);

//[DNSCurve Keys] block
	memset(DNSCurveConfigurationParameter->Client_PublicKey, 0, crypto_box_PUBLICKEYBYTES);
	sodium_memzero(DNSCurveConfigurationParameter->Client_SecretKey, crypto_box_SECRETKEYBYTES);
	sodium_memzero(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES);
	sodium_memzero(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES);
	sodium_memzero(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES);
	sodium_memzero(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);

//[DNSCurve Magic Number] block
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	memset(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);

//Default settings
	DNSCurveConfigurationParameter->DNSCurveProtocol_Network = REQUEST_MODE_NETWORK::BOTH;
	DNSCurveConfigurationParameter->DNSCurveProtocol_Transport = REQUEST_MODE_TRANSPORT::UDP;
	DNSCurveConfigurationParameter->DNSCurvePayloadSize = EDNS_PACKET_MINSIZE;
#if defined(PLATFORM_WIN)
	DNSCurveConfigurationParameter->DNSCurve_SocketTimeout_Reliable = DNSCURVE_DEFAULT_RELIABLE_SOCKET_TIMEOUT;
	DNSCurveConfigurationParameter->DNSCurve_SocketTimeout_Unreliable = DNSCURVE_DEFAULT_UNRELIABLE_SOCKET_TIMEOUT;
#elif (defined(PLATFORM_FREEBSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS))
	DNSCurveConfigurationParameter->DNSCurve_SocketTimeout_Reliable.tv_sec = DNSCURVE_DEFAULT_RELIABLE_SOCKET_TIMEOUT;
	DNSCurveConfigurationParameter->DNSCurve_SocketTimeout_Unreliable.tv_sec = DNSCURVE_DEFAULT_UNRELIABLE_SOCKET_TIMEOUT;
#endif
	DNSCurveConfigurationParameter->KeyRecheckTime = DNSCURVE_DEFAULT_RECHECK_TIME * SECOND_TO_MILLISECOND;

	return;
}

//DNSCurveConfigurationTable class destructor
DNSCurveConfigurationTable::~DNSCurveConfigurationTable(
	void)
{
//[DNSCurve Database] block
	delete DatabaseName;
	DatabaseName = nullptr;
#if (defined(PLATFORM_FREEBSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS))
	delete DatabaseName_MBS;
	DatabaseName_MBS = nullptr;
#endif
	delete Database_Target_Server_Main_IPv6;
	delete Database_Target_Server_Alternate_IPv6;
	delete Database_Target_Server_Main_IPv4;
	delete Database_Target_Server_Alternate_IPv4;
	delete Database_LineData;
	Database_Target_Server_Main_IPv6 = nullptr;
	Database_Target_Server_Alternate_IPv6 = nullptr;
	Database_Target_Server_Main_IPv4 = nullptr;
	Database_Target_Server_Alternate_IPv4 = nullptr;
	Database_LineData = nullptr;

//[DNSCurve Addresses] block
	delete[] DNSCurve_Target_Server_Main_IPv6.ProviderName;
	delete[] DNSCurve_Target_Server_Alternate_IPv6.ProviderName;
	delete[] DNSCurve_Target_Server_Main_IPv4.ProviderName;
	delete[] DNSCurve_Target_Server_Alternate_IPv4.ProviderName;
	DNSCurve_Target_Server_Main_IPv6.ProviderName = nullptr;
	DNSCurve_Target_Server_Alternate_IPv6.ProviderName = nullptr;
	DNSCurve_Target_Server_Main_IPv4.ProviderName = nullptr;
	DNSCurve_Target_Server_Alternate_IPv4.ProviderName = nullptr;

//[DNSCurve Keys] block
	delete[] Client_PublicKey;
	sodium_free(Client_SecretKey);
	sodium_free(DNSCurve_Target_Server_Main_IPv6.PrecomputationKey);
	sodium_free(DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey);
	sodium_free(DNSCurve_Target_Server_Main_IPv4.PrecomputationKey);
	sodium_free(DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey);
	delete[] DNSCurve_Target_Server_Main_IPv6.ServerPublicKey;
	delete[] DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey;
	delete[] DNSCurve_Target_Server_Main_IPv4.ServerPublicKey;
	delete[] DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey;
	delete[] DNSCurve_Target_Server_Main_IPv6.ServerFingerprint;
	delete[] DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint;
	delete[] DNSCurve_Target_Server_Main_IPv4.ServerFingerprint;
	delete[] DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint;
	Client_PublicKey = nullptr;
	Client_SecretKey = nullptr;
	DNSCurve_Target_Server_Main_IPv6.PrecomputationKey = nullptr;
	DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey = nullptr;
	DNSCurve_Target_Server_Main_IPv4.PrecomputationKey = nullptr;
	DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey = nullptr;
	DNSCurve_Target_Server_Main_IPv6.ServerPublicKey = nullptr;
	DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey = nullptr;
	DNSCurve_Target_Server_Main_IPv4.ServerPublicKey = nullptr;
	DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey = nullptr;
	DNSCurve_Target_Server_Main_IPv6.ServerFingerprint = nullptr;
	DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint = nullptr;
	DNSCurve_Target_Server_Main_IPv4.ServerFingerprint = nullptr;
	DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint = nullptr;

//[DNSCurve Magic Number] block
	delete[] DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber;
	delete[] DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber;
	delete[] DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber;
	delete[] DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber;
	delete[] DNSCurve_Target_Server_Main_IPv6.SendMagicNumber;
	delete[] DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber;
	delete[] DNSCurve_Target_Server_Main_IPv4.SendMagicNumber;
	delete[] DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber;
	DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber = nullptr;
	DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber = nullptr;
	DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber = nullptr;
	DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber = nullptr;
	DNSCurve_Target_Server_Main_IPv6.SendMagicNumber = nullptr;
	DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber = nullptr;
	DNSCurve_Target_Server_Main_IPv4.SendMagicNumber = nullptr;
	DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber = nullptr;

	return;
}

//DNSCurveConfigurationTable class SetToMonitorItem function
void DNSCurveConfigurationTable::SetToMonitorItem(
	void)
{
//Delete and reset pointers.
	delete DatabaseName;
	DatabaseName = nullptr;
#if (defined(PLATFORM_FREEBSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS))
	delete DatabaseName_MBS;
	DatabaseName_MBS = nullptr;
#endif
	delete Database_Target_Server_Main_IPv6;
	delete Database_Target_Server_Alternate_IPv6;
	delete Database_Target_Server_Main_IPv4;
	delete Database_Target_Server_Alternate_IPv4;
	Database_Target_Server_Main_IPv6 = nullptr;
	Database_Target_Server_Alternate_IPv6 = nullptr;
	Database_Target_Server_Main_IPv4 = nullptr;
	Database_Target_Server_Alternate_IPv4 = nullptr;
	delete[] DNSCurve_Target_Server_Main_IPv6.ProviderName;
	delete[] DNSCurve_Target_Server_Alternate_IPv6.ProviderName;
	delete[] DNSCurve_Target_Server_Main_IPv4.ProviderName;
	delete[] DNSCurve_Target_Server_Alternate_IPv4.ProviderName;
	DNSCurve_Target_Server_Main_IPv6.ProviderName = nullptr;
	DNSCurve_Target_Server_Alternate_IPv6.ProviderName = nullptr;
	DNSCurve_Target_Server_Main_IPv4.ProviderName = nullptr;
	DNSCurve_Target_Server_Alternate_IPv4.ProviderName = nullptr;

	return;
}

//DNSCurveConfigurationTable class MonitorItemToUsing function
void DNSCurveConfigurationTable::MonitorItemToUsing(
	DNSCurveConfigurationTable * const DNSCurveConfigurationParameter)
{
	DNSCurveConfigurationParameter->DNSCurve_SocketTimeout_Reliable = DNSCurve_SocketTimeout_Reliable;
	DNSCurveConfigurationParameter->DNSCurve_SocketTimeout_Unreliable = DNSCurve_SocketTimeout_Unreliable;
	DNSCurveConfigurationParameter->KeyRecheckTime = KeyRecheckTime;

//[DNSCurve Keys] block
	if (DNSCurveConfigurationParameter->Client_PublicKey != nullptr && !CheckEmptyBuffer(Client_PublicKey, crypto_box_PUBLICKEYBYTES) &&
		memcmp(DNSCurveConfigurationParameter->Client_PublicKey, Client_PublicKey, crypto_box_PUBLICKEYBYTES) != 0)
			memcpy_s(DNSCurveConfigurationParameter->Client_PublicKey, crypto_box_PUBLICKEYBYTES, Client_PublicKey, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->Client_SecretKey != nullptr && sodium_is_zero(Client_SecretKey, crypto_box_PUBLICKEYBYTES) == 0 &&
		sodium_memcmp(DNSCurveConfigurationParameter->Client_SecretKey, Client_SecretKey, crypto_box_PUBLICKEYBYTES) != 0)
			memcpy_s(DNSCurveConfigurationParameter->Client_SecretKey, crypto_box_PUBLICKEYBYTES, Client_SecretKey, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.PrecomputationKey != nullptr &&
		sodium_is_zero(DNSCurve_Target_Server_Main_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES) == 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES, DNSCurve_Target_Server_Main_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey != nullptr &&
		sodium_is_zero(DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES) == 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES, DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.PrecomputationKey != nullptr &&
		sodium_is_zero(DNSCurve_Target_Server_Main_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES) == 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES, DNSCurve_Target_Server_Main_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey != nullptr &&
		sodium_is_zero(DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES) == 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES, DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ServerPublicKey != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES) &&
		memcmp(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ServerPublicKey, DNSCurve_Target_Server_Main_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES) != 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Main_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES) &&
		memcmp(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey, DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES) != 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ServerPublicKey != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES) &&
		memcmp(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ServerPublicKey, DNSCurve_Target_Server_Main_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES) != 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Main_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES) &&
		memcmp(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey, DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES) != 0)
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ServerFingerprint != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv6.ServerFingerprint, crypto_box_PUBLICKEYBYTES))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ServerFingerprint, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Main_IPv6.ServerFingerprint, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint, crypto_box_PUBLICKEYBYTES))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ServerFingerprint != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv4.ServerFingerprint, crypto_box_PUBLICKEYBYTES))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ServerFingerprint, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Main_IPv4.ServerFingerprint, crypto_box_PUBLICKEYBYTES);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint, crypto_box_PUBLICKEYBYTES))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint, crypto_box_PUBLICKEYBYTES, DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint, crypto_box_PUBLICKEYBYTES);

//[DNSCurve Magic Number] block
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.SendMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv6.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv6.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Main_IPv6.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.SendMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Main_IPv4.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Main_IPv4.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Main_IPv4.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber != nullptr &&
		!CheckEmptyBuffer(DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN))
			memcpy_s(DNSCurveConfigurationParameter->DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN, DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber, DNSCURVE_MAGIC_QUERY_LEN);

	return;
}

//DNSCurveConfigurationTable class MonitorItemReset function
void DNSCurveConfigurationTable::MonitorItemReset(
	void)
{
#if defined(PLATFORM_WIN)
	DNSCurve_SocketTimeout_Reliable = DNSCURVE_DEFAULT_RELIABLE_SOCKET_TIMEOUT;
	DNSCurve_SocketTimeout_Unreliable = DNSCURVE_DEFAULT_UNRELIABLE_SOCKET_TIMEOUT;
#elif (defined(PLATFORM_FREEBSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS))
	DNSCurve_SocketTimeout_Reliable.tv_sec = DNSCURVE_DEFAULT_RELIABLE_SOCKET_TIMEOUT;
	DNSCurve_SocketTimeout_Reliable.tv_usec = 0;
	DNSCurve_SocketTimeout_Unreliable.tv_sec = DNSCURVE_DEFAULT_UNRELIABLE_SOCKET_TIMEOUT;
	DNSCurve_SocketTimeout_Unreliable.tv_usec = 0;
#endif
	KeyRecheckTime = DNSCURVE_DEFAULT_RECHECK_TIME * SECOND_TO_MILLISECOND;

//[DNSCurve database] block
	if (Database_LineData != nullptr)
	{
		Database_LineData->clear();
		Database_LineData->shrink_to_fit();
	}

//[DNSCurve Keys] block
	if (Client_PublicKey != nullptr)
		memset(Client_PublicKey, 0, crypto_box_PUBLICKEYBYTES);
	if (Client_SecretKey != nullptr)
		sodium_memzero(Client_SecretKey, crypto_box_SECRETKEYBYTES);
	if (DNSCurve_Target_Server_Main_IPv6.PrecomputationKey != nullptr)
		sodium_memzero(DNSCurve_Target_Server_Main_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey != nullptr)
		sodium_memzero(DNSCurve_Target_Server_Alternate_IPv6.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurve_Target_Server_Main_IPv4.PrecomputationKey != nullptr)
		sodium_memzero(DNSCurve_Target_Server_Main_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey != nullptr)
		sodium_memzero(DNSCurve_Target_Server_Alternate_IPv4.PrecomputationKey, crypto_box_BEFORENMBYTES);
	if (DNSCurve_Target_Server_Main_IPv6.ServerPublicKey != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv6.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	if (DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv6.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	if (DNSCurve_Target_Server_Main_IPv4.ServerPublicKey != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv4.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	if (DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv4.ServerPublicKey, 0, crypto_box_PUBLICKEYBYTES);
	if (DNSCurve_Target_Server_Main_IPv6.ServerFingerprint != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv6.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);
	if (DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv6.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);
	if (DNSCurve_Target_Server_Main_IPv4.ServerFingerprint != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv4.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);
	if (DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv4.ServerFingerprint, 0, crypto_box_PUBLICKEYBYTES);

//[DNSCurve Magic Number] block
	if (DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv6.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv6.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv4.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv4.ReceiveMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurve_Target_Server_Main_IPv6.SendMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv6.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv6.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurve_Target_Server_Main_IPv4.SendMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Main_IPv4.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);
	if (DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber != nullptr)
		memset(DNSCurve_Target_Server_Alternate_IPv4.SendMagicNumber, 0, DNSCURVE_MAGIC_QUERY_LEN);

	return;
}

DNSCurveSocketSelectingTable::DNSCurveSocketSelectingTable(
	void)
{
	ServerType = DNSCURVE_SERVER_TYPE::NONE;
	PrecomputationKey = nullptr;
	ReceiveMagicNumber = nullptr;
	SendBuffer = nullptr;
	SendSize = 0;
	RecvLen = 0;
	IsPacketDone = false;

	return;
}
#endif

#if defined(ENABLE_TLS)
#if defined(PLATFORM_WIN)
SSPIHandleTable::SSPIHandleTable(
	void)
{
	memset(&ClientCredentials, 0, sizeof(ClientCredentials));
	memset(&ContextHandle, 0, sizeof(ContextHandle));
	InputFlags = 0;
	memset(&StreamSizes, 0, sizeof(StreamSizes));
	LastReturnValue = 0;

	return;
}

//SSPIHandleTable class destructor
SSPIHandleTable::~SSPIHandleTable(
	void)
{
	FreeCredentialsHandle(&ClientCredentials);
	DeleteSecurityContext(&ContextHandle);

	return;
}
#elif (defined(PLATFORM_FREEBSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS))
OpenSSLContextTable::OpenSSLContextTable(
	void)
{
	MethodContext = nullptr;
	SessionBIO = nullptr;
	SessionData = nullptr;
	Protocol_Network = 0;
	Protocol_Transport = 0;
	Socket = INVALID_SOCKET;

	return;
}

//OpenSSLContextTable class destructor
OpenSSLContextTable::~OpenSSLContextTable(
	void)
{
//Free all sessions.
	if (SessionBIO != nullptr)
	{
		BIO_free_all(SessionBIO);
		SessionBIO = nullptr;
	}

//Free all method context.
	if (MethodContext != nullptr)
	{
		SSL_CTX_free(MethodContext);
		MethodContext = nullptr;
	}

//Close all sockets.
	if (SocketSetting(Socket, SOCKET_SETTING_TYPE::INVALID_CHECK, false, nullptr))
		SocketSetting(Socket, SOCKET_SETTING_TYPE::CLOSE, false, nullptr);

	return;
}
#endif
#endif


// calculate heat conduction in zeta-direction of element (i,j)

// to do: temperature dependent density not implemented correctly yet!
//        better implementation of volume evaporation
//        locally varying material properties?

int HeatConduction::Solve(int i, int j, prec &vn)
{
    int k, ia, ipa, ja, jpa;
    prec hsaisai, hsaizta, hsaieta, hetaeta, hetazta, qfluxt, dvol,
        sumr, term, g11, g12, g22, r1t, vmax, thetamin, thetamin0,
        dthetamin, thetamax, thetamax0, dthetamax, gamma, abscoeff;
    cmplx index;
    rmmatrix MetricTensor(3, 3);
    TPoint3D LaplaceSai;
    bool bAnalyt;

    TempSai.Reallocate(Grid.kVolNodes); // reallocate arrays
    PowerDensity.Reallocate(Grid.kVolNodes);
    m.Reallocate(Grid.kVolNodes + 2);

    if (Solid(i, j, Grid.kVolNodes).ndNode.z < Grid.ndWpThickness)
        m(Grid.kVolNodes).a = 0.0; // temp fixed
    else
        m(Grid.kVolNodes).a = -1.0; // drilled through => gradient fixed
    m(Grid.kVolNodes).b = 1.0;
    m(Grid.kVolNodes).c = 0.0;
    m(Grid.kVolNodes).rhs = 0.0;

    for (k = Grid.kVolNodes - 1; k >= 1; k--) // matrix setup
    {
        Solid.CalcBaseVect(i, j, k); // base vectors
        abszta = Solid.CalcMetricTensor(i, j, k, MetricTensor, LaplaceSai);
        SolidOld.CalcTempDerivative(i, j, k, TempSai(k), hsaisai, hetaeta, hsaieta,
                                    hsaizta, hetazta); // calculate T-derivatives

        if (k > 1) // inner nodes
        {
            g11 = Solid(i, j, k).xsai.Norm();
            g22 = Solid(i, j, k).xeta.Norm();
            g12 = Solid(i, j, k).xsai * Solid(i, j, k).xeta;
            dvol = sqrt(g11 * g22 - g12 * g12) / abszta; // volume of cell
            PowerDensity(k) = Solid(i, j, k).ndHeat / dvol; // convert to power density
            gamma = MetricTensor(0, 0) * hsaisai + MetricTensor(1, 1) * hetaeta + MetricTensor(0, 1) * hsaieta + MetricTensor(0, 2) * hsaizta + MetricTensor(1, 2) * hetazta + LaplaceSai.x * TempSai(k).x + LaplaceSai.y * TempSai(k).y;

            m(k).at = 0.5 * LaplaceSai.z - MetricTensor(2, 2);
            m(k).bt = 2.0 * MetricTensor(2, 2);
            m(k).ct = -0.5 * LaplaceSai.z - MetricTensor(2, 2);
            // explicit expression
            m(k).rhst = gamma + PowerDensity(k) * Laser.ndPower;
            m(k).ndTemp = Solid(i, j, k).ndTemp; // temperature estimate
        }
        else // surface node
        {
            dvol = 0.5 * SolSurf(i, j).ndArea / abszta; // volume of (half) cell
            // convert to power density
            PowerDensity(k) = Solid(i, j, k).ndHeat / dvol;
            gamma = MetricTensor(0, 0) * hsaisai + MetricTensor(1, 1) * hetaeta + MetricTensor(0, 1) * hsaieta + MetricTensor(0, 2) * hsaizta + MetricTensor(1, 2) * hetazta + LaplaceSai.x * TempSai(k).x + LaplaceSai.y * TempSai(k).y;
            r1t = 2.0 * (MetricTensor(0, 2) * TempSai(k).x + MetricTensor(1, 2) * TempSai(k).y);

            qfluxt = (SolSurf(i, j).ndDirAbs + SolSurf(i, j).ndMultAbs) * Laser.ndPower * abszta; // for maximum ablation velocity

            m(k).at = 0.0;
            m(k).ct = -2.0 * MetricTensor(2, 2) - LaplaceSai.z;
            m(k).bt = -m(k).ct;
            m(k).rhst = gamma + PowerDensity(k) * Laser.ndPower + r1t;
            m(k).ndTemp = Solid(i, j, k).ndTemp;
        }
    }

    sumr = 0.0;
    Solid.LocalKlTangent = 0; // calc inner grid direction by averaging
    for (ia = -Grid.iWarpAverage; ia <= Grid.iWarpAverage; ia++)
    {
        ipa = i + ia;
        if (ipa >= 1 && ipa <= Grid.iVolNodes)
        {
            for (ja = -Grid.iWarpAverage; ja <= Grid.iWarpAverage; ja++)
            {
                if (ia != 0 || ja != 0)
                {
                    jpa = j + ja;
                    if (jpa >= 1 && jpa <= Grid.jVolNodes)
                    {
                        term = 1.0 / pow((SolidOld(i, j, 1).ndNode - SolidOld(ipa, jpa, 1).ndNode).Norm(),
                                         Grid.iWarpPower);
                        sumr += term;
                        Solid.LocalKlTangent += SolSurf(ipa, jpa).Normal * term;
                    }
                }
            }
        }
    }
    Solid.LocalKlTangent.z += sumr * Grid.TangentDir;
    Solid.LocalKlTangent.Normalize();

    bAnalyt = false;
    // maximum recession
    saitmax.z = -qfluxt / Material.ndStefan.Get(m(1).ndTemp);
    // speed
    vmax = max(-saitmax.z / abszta, 1e-30); // vmax in phys. domain
    // estimations for temperature interval
    thetamin = Material.GetSurfTemp(Simulation.ndMinVapVelo, m(1).ndTemp);
    thetamax = min(Material.GetSurfTemp(vmax, m(1).ndTemp),
                   Material.ndCriticalTemp);

    if (!Simulation.bHeatConduct) // no heat conduction
    {
        bAnalyt = true; // analytical solution for heat conduction
        if (qfluxt == 0) // no heat input => final temp = 0
            thetamax = 0;
        if (thetamax > m(1).ndTemp) // heating
            m(1).ndTemp += (thetamax - m(1).ndTemp) * min(Simulation.ndDeltat / Simulation.ndHeatingDelay, 1.0);
        else // cooling
        {
            m(1).ndTemp += (thetamax - m(1).ndTemp) * min(Simulation.ndDeltat / Simulation.ndCoolingDelay, 1.0);
            if (m(1).ndTemp < 0)
                m(1).ndTemp = 0;
        }
        CalcRecession(i, j, m(1).ndTemp, vn); // get recession speed
        Solid.GridMove(i, j, vn); // shift grid
    }
    else if (vmax < Simulation.ndMinVapVelo && // no iteration if material
             m(1).ndTemp < thetamin) // is cool and no significant heating
    {
        vn = max(vmax, (prec)1e-30);
        thetamin = Material.GetSurfTemp(vn, m(1).ndTemp);
        if (CalcTemp(i, j, thetamin, vn) < 0) // only one iteration
            return -1;
    }
    else // solve heat conduction
    {
        if (CalcTemp(i, j, thetamin, vn) < 0) // first estimate of temperatures
            return -1; // with negligable evaporation
        if (m(1).ndTemp <= thetamin) // no iteration if almost cold
        {
            if (CalcTemp(i, j, m(1).ndTemp, vn) < 0) // one more iteration
                return -1;
        }
        else
        {
            thetamin0 = thetamin;
            dthetamin = m(1).ndTemp - thetamin; // change of minumum temperature

            if (vmax < Simulation.ndMinVapVelo) // correct maximum temperature
                thetamax = min(m(1).ndTemp * 1.5, Material.ndCriticalTemp);
            else
                thetamax = max(thetamax, m(1).ndTemp) + 1e-04;
            if (CalcTemp(i, j, thetamax, vn) < 0) // first estimate with maximum
                return -1; // ablation velo
            thetamax0 = thetamax;
            dthetamax = m(1).ndTemp - thetamax;

            if (dthetamax > 0) // larger than maximum temperature
            {
                WarningFunction("  ****** WARNING: multiple roots possible for "
                                "i=%2i, j=%2i; searching for largest root *****\n"
                                "          HLO=%7.5lf, FLO=%12.5lf\n"
                                "          HHI=%7.5lf, FHI=%12.5lf\n"
                                "  HOLD(I,J,1)=%7.5lf",
                                i, j, thetamin, dthetamin,
                                thetamax, dthetamax, SolidOld(i, j, 1).ndTemp);
                for (ia = 0; ia < 1000; ia++)
                {
                    thetamin = thetamax - 1e-3 * (thetamax0 - thetamin0);
                    if (CalcTemp(i, j, thetamin, vn) < 0) // correct lower temperature
                        return -1;
                    dthetamin = m(1).ndTemp - thetamin; // change of minumum temperature
                    if (dthetamin >= 0) // continue with increased lower limit
                        break;
                    thetamax = thetamin;
                    dthetamax = dthetamin;
                }
                if (ia >= 1000)
                {
                    ErrorFunction("*** Maximum iterations to find T_surface exceeded at "
                                  "I=%2i, J=%2i",
                                  i, j);
                    return -1;
                }
            }
            else if (dthetamax < 0) // converging => find root
            {
                if (FindRoot(i, j, thetamin, thetamax, dthetamin, dthetamax, vn, thetamax0) < 0)
                    return -1;
            }
        }
    }

    for (k = 1; k <= Grid.kVolNodes; k++) // temperatures found
    {
        if (m(1).ndTemp < 0) // restrict to room temperature
            Solid(i, j, k).ndTemp = 0;
        else if (k == 1 || !bAnalyt)
            Solid(i, j, k).ndTemp = m(k).ndTemp;
        else
        {
            if (vmax < Simulation.ndMinVapVelo)
                Solid(i, j, k).ndTemp = 0;
            else // analytical expressio for stationary ablation
            {
                abscoeff = Material.GetAbsIndex(m(1).ndTemp, index);
                prec dz = Solid(i, j, k).ndNode.z - Solid(i, j, 1).ndNode.z;
                Solid(i, j, k).ndTemp = (Laser.ndAvePower * Laser.ndPower / (vmax - abscoeff) * (exp(-abscoeff * dz) - exp(-vmax * dz)) + Solid(i, j, 1).ndTemp * exp(-vmax * dz) - Solid(i, j, k).ndTemp) * // dtheta
                                        min(Simulation.ndDeltat / Simulation.ndHeatingDelay, 1.0); // relax
            }
        }
    }

    Solid.ndVapRate += vn * SolSurf(i, j).ndArea; // volumetric removal rate
    if (vn > Solid.ndMaxVelo)
        Solid.ndMaxVelo = vn; // maximum recession speed
    return 0;
}

// calculate temperature for estimated surface temperature harr

int HeatConduction::CalcTemp(int i, int j, prec &theta, prec &vn)
{
    int k;
    prec fadti, ac;

    CalcRecession(i, j, theta, vn);
    Solid.GridMove(i, j, vn);

    for (k = 1; k < Grid.kVolNodes; k++)
        m(k).fa = Material.ndDiffusivity.Get(m(k).ndTemp);

    for (k = 2; k < Grid.kVolNodes; k++) // set up tridiagonal matrix
    {
        fadti = 1.0 / (Simulation.ndDeltat * m(k).fa);
        ac = 0.5 * Solid(i, j, k).sait.z / m(k).fa;
        m(k).a = m(k).at - ac;
        m(k).b = m(k).bt + fadti;
        m(k).c = m(k).ct + ac;
        if (Simulation.bSurfVapor || saitmax.z == 0) // surface evaporation
            m(k).rhs = m(k).rhst + SolidOld(i, j, k).ndTemp * fadti - (Solid(i, j, k).sait.x * TempSai(k).x + Solid(i, j, k).sait.y * TempSai(k).y) / m(k).fa;
        else // volume evaporation
            m(k).rhs = m(k).rhst + SolidOld(i, j, k).ndTemp * fadti - (Solid(i, j, k).sait.x * TempSai(k).x + Solid(i, j, k).sait.y * TempSai(k).y) / m(k).fa - PowerDensity(k) * Laser.ndPower * Solid(i, j, 1).sait.z / saitmax.z;
    }

    fadti = 1.0 / (Simulation.ndDeltat * m(1).fa);
    ac = Solid(i, j, 1).sait.z / m(1).fa;
    m(1).b = m(1).bt + fadti - ac;
    m(1).c = m(1).ct + ac;
    if (Simulation.bSurfVapor || saitmax.z == 0) // surface evaporation
        m(1).rhs = m(1).rhst + SolidOld(i, j, 1).ndTemp * fadti + 2.0 * Material.ndStefan.Get(m(1).ndTemp) * Solid(i, j, 1).sait.z - (Solid(i, j, 1).sait.x * TempSai(1).x + Solid(i, j, 1).sait.y * TempSai(1).y) / m(1).fa;
    else // volume evaporation
        m(1).rhs = m(1).rhst + SolidOld(i, j, 1).ndTemp * fadti - (Solid(i, j, 1).sait.x * TempSai(1).x + Solid(i, j, 1).sait.y * TempSai(1).y) / m(1).fa - PowerDensity(1) * Laser.ndPower * Solid(i, j, 1).sait.z / saitmax.z;
    m(1).a = 0.0;

    if (m.Solve(Grid.kVolNodes) < 0) // solve matrix
        return -1;

    return 0;
}

// iteration of surface temperature

int HeatConduction::FindRoot(int i, int j, prec &hlo, prec &hhi, prec &flo,
                             prec &fhi, prec &vn, prec harrmax)
{
    int knt;
    prec hmid, fmid, s, hnew, fnew, relax, delta;

    for (knt = 1; knt <= 300; knt++)
    {
        hmid = 0.5 * (hhi + hlo); // average of interval
        if (CalcTemp(i, j, hmid, vn) < 0)
            return -1;
        fmid = m(1).ndTemp - hmid; // gradient of average interval
        delta = fmid * fmid - flo * fhi;
        if (delta < 0)
            break;
        s = sqrt(delta);
        if (s == 0)
            return 0;
        hnew = hmid + (hmid - hlo) * fmid / s;
        if (CalcTemp(i, j, hnew, vn) < 0)
            return -1;
        if (fabs(hnew - m(1).ndTemp) <= Simulation.ndTempTol)
            return 0; // root found
        fnew = m(1).ndTemp - hnew;
        if (fmid * fnew < 0)
        {
            if (fmid > 0)
            {
                hlo = hmid;
                flo = fmid;
                hhi = hnew;
                fhi = fnew;
            }
            else
            {
                hlo = hnew;
                flo = fnew;
                hhi = hmid;
                fhi = fmid;
            }
        }
        else
        {
            if (flo * fnew < 0)
            {
                hhi = hnew;
                fhi = fnew;
            }
            else
            {
                hlo = hnew;
                flo = fnew;
            }
        }
    }

    // Newton iteration starting at harrmax if no convergence

    hhi = harrmax;
    CalcTemp(i, j, hhi, vn);
    if (m(1).ndTemp > Material.ndCriticalTemp)
    {
        hhi = Material.ndCriticalTemp;
        CalcTemp(i, j, hhi, vn);
    }
    fhi = m(1).ndTemp - hhi; // DT = f(hhi)
    while (fabs(fhi) > Simulation.ndTempTol / 1e7)
    {
        relax = 1;
        hnew = hhi + Simulation.ndTempTol;
        CalcTemp(i, j, hnew, vn);
        fnew = m(1).ndTemp - hnew; // DT = f(hhi+htol) for f'(hhi)
        do
        {
            if (relax < Simulation.ndTempTol / 1e8)
            {
                ErrorFunction("  **** ITERATION TO FIND HARR DID NOT CONVERGE FOR"
                              " I=%2i, J=%2i\n  **** HARR=%7.5lf, FARR=%12.4lf",
                              i, j, hnew, fnew);
                return 0;
            }
            hnew = hhi - relax * fhi * Simulation.ndTempTol / (fnew - fhi);
            CalcTemp(i, j, hnew, vn);
            flo = m(1).ndTemp - hnew;
            relax /= 2;
        } while (fabs(flo) >= fabs(fhi));
        fhi = flo;
        hhi = hnew;
    }

    return 0;
}

// calculate evaporation rate vn(harr) and surface displacement

void HeatConduction::CalcRecession(int i, int j, prec &theta, prec &vn)
{
    theta = max(theta, 0.);
    vn = Material.GetEvapVelocity(theta);
    Solid(i, j, 1).sait.z = -vn * abszta; // velocity in comput. domain
}

// solve tridiagonal matrix A*u(i-1)+B*u(i)+C*u(i+1)=R for i=0..N-1

int TTridagMatrix::Solve(int n)
{
    rvector gam(GetSize());
    prec bet;
    int j;

    bet = At(1).b;
    if (bet == 0)
    {
        ErrorFunction("ERROR: bad matrix - b(1)=0");
        return -1;
    }
    At(1).ndTemp = At(1).rhs / bet;
    for (j = 2; j <= n; j++)
    {
        gam(j) = At(j - 1).c / bet;
        bet = At(j).b - At(j).a * gam(j);
        if (bet == 0)
        {
            ErrorFunction("ERROR: division by 0 in tridag");
            return -1;
        }
        At(j).ndTemp = (At(j).rhs - At(j).a * At(j - 1).ndTemp) / bet;
    }
    for (j = n - 1; j >= 1; j--)
        At(j).ndTemp -= gam(j + 1) * At(j + 1).ndTemp;

    return 0;
}


bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color stm) {

  assert(file_of(wpsq) <= FILE_D);

  return KPKBitbase[index(stm, bksq, wksq, wpsq)];
}

/*
  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
*/

#include <cassert>
#include <vector>
#include <bitset>

#include "bitboard.h"
#include "types.h"

namespace Stockfish {

namespace {

  // There are 24 possible pawn squares: files A to D and ranks from 2 to 7.
  // Positions with the pawn on files E to H will be mirrored before probing.
  constexpr unsigned MAX_INDEX = 2*24*64*64; // stm * psq * wksq * bksq = 196608

  std::bitset<MAX_INDEX> KPKBitbase;

  // A KPK bitbase index is an integer in [0, IndexMax] range
  // Information is mapped in a way that minimizes the number of iterations:
  // bit  0- 5: white king square (from SQ_A1 to SQ_H8)
  // bit  6-11: black king square (from SQ_A1 to SQ_H8)
  // bit    12: side to move (WHITE or BLACK)
  // bit 13-14: white pawn file (from FILE_A to FILE_D)
  // bit 15-17: white pawn RANK_7 - rank (from RANK_7 - RANK_7 to RANK_7 - RANK_2)
  unsigned index(Color stm, Square bksq, Square wksq, Square psq) {
    return int(wksq) | (bksq << 6) | (stm << 12) | (file_of(psq) << 13) | ((RANK_7 - rank_of(psq)) << 15);
  }

  enum Result {
    INVALID = 0,
    UNKNOWN = 1,
    DRAW    = 2,
    WIN     = 4
  };

  Result& operator|=(Result& r, Result v) { return r = Result(r | v); }

  struct KPKPosition {
    KPKPosition() = default;
    explicit KPKPosition(unsigned idx);
    operator Result() const { return result; }
    Result classify(const std::vector<KPKPosition>& db);

    Color stm;
    Square ksq[COLOR_NB], psq;
    Result result;
  };

} // namespace

void Bitbases::init() {

#ifdef LARGEBOARDS
    // Bitbases are not working for large-board version
    return;
#endif

  std::vector<KPKPosition> db(MAX_INDEX);
  unsigned idx, repeat = 1;

  // Initialize db with known win / draw positions
  for (idx = 0; idx < MAX_INDEX; ++idx)
      db[idx] = KPKPosition(idx);

  // Iterate through the positions until none of the unknown positions can be
  // changed to either wins or draws (15 cycles needed).
  while (repeat)
      for (repeat = idx = 0; idx < MAX_INDEX; ++idx)
          repeat |= (db[idx] == UNKNOWN && db[idx].classify(db) != UNKNOWN);

  // Fill the bitbase with the decisive results
  for (idx = 0; idx < MAX_INDEX; ++idx)
      if (db[idx] == WIN)
          KPKBitbase.set(idx);
}

namespace {

  KPKPosition::KPKPosition(unsigned idx) {

    ksq[WHITE] = Square((idx >>  0) & 0x3F);
    ksq[BLACK] = Square((idx >>  6) & 0x3F);
    stm        = Color ((idx >> 12) & 0x01);
    psq        = make_square(File((idx >> 13) & 0x3), Rank(RANK_7 - ((idx >> 15) & 0x7)));

    // Invalid if two pieces are on the same square or if a king can be captured
    if (   distance(ksq[WHITE], ksq[BLACK]) <= 1
        || ksq[WHITE] == psq
        || ksq[BLACK] == psq
        || (stm == WHITE && (pawn_attacks_bb(WHITE, psq) & ksq[BLACK])))
        result = INVALID;

    // Win if the pawn can be promoted without getting captured
    else if (   stm == WHITE
             && rank_of(psq) == RANK_7
             && ksq[WHITE] != psq + NORTH
             && (    distance(ksq[BLACK], psq + NORTH) > 1
                 || (distance(ksq[WHITE], psq + NORTH) == 1)))
        result = WIN;

    // Draw if it is stalemate or the black king can capture the pawn
    else if (   stm == BLACK
             && (  !(attacks_bb<KING>(ksq[BLACK]) & ~(attacks_bb<KING>(ksq[WHITE]) | pawn_attacks_bb(WHITE, psq)))
                 || (attacks_bb<KING>(ksq[BLACK]) & ~attacks_bb<KING>(ksq[WHITE]) & psq)))
        result = DRAW;

    // Position will be classified later
    else
        result = UNKNOWN;
  }

  Result KPKPosition::classify(const std::vector<KPKPosition>& db) {

    // White to move: If one move leads to a position classified as WIN, the result
    // of the current position is WIN. If all moves lead to positions classified
    // as DRAW, the current position is classified as DRAW, otherwise the current
    // position is classified as UNKNOWN.
    // Black to move: If one move leads to a position classified as DRAW, the result
    // of the current position is DRAW. If all moves lead to positions classified
    // as WIN, the position is classified as WIN, otherwise the current position is
    // classified as UNKNOWN.
    const Result Good = (stm == WHITE ? WIN   : DRAW);
    const Result Bad  = (stm == WHITE ? DRAW  : WIN);

    Result r = INVALID;
    Bitboard b = attacks_bb<KING>(ksq[stm]);

    while (b)
        r |= stm == WHITE ? db[index(BLACK, ksq[BLACK], pop_lsb(b), psq)]
                          : db[index(WHITE, pop_lsb(b), ksq[WHITE], psq)];

    if (stm == WHITE)
    {
        if (rank_of(psq) < RANK_7)      // Single push
            r |= db[index(BLACK, ksq[BLACK], ksq[WHITE], psq + NORTH)];

        if (   rank_of(psq) == RANK_2   // Double push
            && psq + NORTH != ksq[WHITE]
            && psq + NORTH != ksq[BLACK])
            r |= db[index(BLACK, ksq[BLACK], ksq[WHITE], psq + NORTH + NORTH)];
    }

    return result = r & Good  ? Good  : r & UNKNOWN ? UNKNOWN : Bad;
  }

} // namespace

} // namespace Stockfish