//---------------------------------------------------------------------------
#include <vcl.h>
#include <tchar.h>
#pragma hdrstop

#include "mDNSServices.h"
#pragma package(smart_init)

#include "mdns.h"

#include "Train_Control.h"
#include "Comm_Thread.h"
//#include "Setup_Control.h"
#include "Debug_Controls.h"

static bool mDNSTerminate;					// mDNS Server Terminate flag

// TODO : This code was a problem if the computer is connected to two or more networks (like with Windows Sandbox)
//        or with both Ethernet and WiFi connections. I did a lot of fixes
//        using __declspec(thread) and to MyHostSaddr's local copy

__declspec( thread ) char addrbuffer[64];
__declspec( thread ) char entrybuffer[256];
__declspec( thread ) char namebuffer[256];
__declspec( thread ) char sendbuffer[1024];

__declspec( thread ) mdns_record_txt_t txtbuffer[128];

__declspec( thread ) struct sockaddr_in service_address_ipv4;
#if __BORLANDC__ >= 0x720
__declspec( thread ) struct sockaddr_in6 service_address_ipv6;
#endif

__declspec( thread ) int has_ipv4;
#if __BORLANDC__ >= 0x720
__declspec( thread ) int has_ipv6;
#endif

__declspec( thread ) uint32_t MyHostSaddr;    // Bug found by Carl Ross
    // A copy of this code is run for each Interface on the computer
    // Without the "__declspec( thread )" modifier, MyHostSaddr is common to
    // all copies rather than unique to each copy

// Data for our service including the mDNS records
typedef struct {
	mdns_string_t service;
	mdns_string_t hostname;
	mdns_string_t service_instance;
	mdns_string_t hostname_qualified;
	struct sockaddr_in address_ipv4;
#if __BORLANDC__ >= 0x720
	struct sockaddr_in6 address_ipv6;
#endif
	int port;
	mdns_record_t record_ptr;
	mdns_record_t record_srv;
	mdns_record_t record_a;
#if __BORLANDC__ >= 0x720
	mdns_record_t record_aaaa;
#endif
	mdns_record_t txt_record[2];
} service_t;


extern TCommThread * ptrTIUCommThread;				// pointer to TIU communications thread


//---------------------------------------------------------------------------
// Following from mdnsjan\mdns.c
//---------------------------------------------------------------------------

#ifdef __cplusplus
extern "C" {
#endif

static int debug(const char* format, ...) {
if (DEBUGGING) {	// if we are debugging display the line
    va_list args;
    int ret;
    char debugline[256];
    va_start(args, format);
    ret = vsnprintf(debugline, sizeof debugline, format, args);
	va_end(args);
	if (ptrTIUCommThread) ptrTIUCommThread->PrintItem(debugline, clGreen);	// debug output displays in Green
    return ret;
	}
return 0;
}

//---------------------------------------------------------------------------

static mdns_string_t
ipv4_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in* addr,
                       size_t addrlen) {
#if __BORLANDC__ >= 0x720
	char host[NI_MAXHOST] = {0};
	char service[NI_MAXSERV] = {0};
	int ret = getnameinfo((const struct sockaddr*)addr, (socklen_t)addrlen, host, NI_MAXHOST,
						  service, NI_MAXSERV, NI_NUMERICSERV | NI_NUMERICHOST);
	int len = 0;
	if (ret == 0) {
		if (addr->sin_port != 0)
			len = snprintf(buffer, capacity, "%s:%s", host, service);
		else
			len = snprintf(buffer, capacity, "%s", host);
	}
#else
	#define NI_MAXHOST      1025
	char host[NI_MAXHOST] = {0};
	char *s = inet_ntoa(addr->sin_addr);
	strncpy(host, s, NI_MAXHOST);
	int len = 0;
	if (s != NULL) {
		if (addr->sin_port != 0)
			len = snprintf(buffer, capacity, "%s:%d", host, MDNS_PORT);
		else
			len = snprintf(buffer, capacity, "%s", host);
	}
#endif
	if (len >= (int)capacity)
		len = (int)capacity - 1;
	mdns_string_t str;
	str.str = buffer;
	str.length = len;
	if (DEBUGGINGX(8)) debug("IPv4 (ipv4_address_to_string) %.*s", MDNS_STRING_FORMAT(str));
	return str;
}
//---------------------------------------------------------------------------
#if __BORLANDC__ >= 0x720
static mdns_string_t
ipv6_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in6* addr,
                       size_t addrlen) {
	char host[NI_MAXHOST] = {0};
	char service[NI_MAXSERV] = {0};
	int ret = getnameinfo((const struct sockaddr*)addr, (socklen_t)addrlen, host, NI_MAXHOST,
	                      service, NI_MAXSERV, NI_NUMERICSERV | NI_NUMERICHOST);
	int len = 0;
	if (ret == 0) {
		if (addr->sin6_port != 0)
			len = snprintf(buffer, capacity, "[%s]:%s", host, service);
		else
			len = snprintf(buffer, capacity, "%s", host);
	}
	if (len >= (int)capacity)
		len = (int)capacity - 1;
	mdns_string_t str;
	str.str = buffer;
	str.length = len;
	if (DEBUGGINGX(8)) debug("IPv6 Address %.*s", MDNS_STRING_FORMAT(str));
	return str;
}
#endif

//---------------------------------------------------------------------------

static mdns_string_t
ip_address_to_string(char* buffer, size_t capacity, const struct sockaddr* addr, size_t addrlen) {
#if __BORLANDC__ >= 0x720
	if (addr->sa_family == AF_INET6)
		return ipv6_address_to_string(buffer, capacity, (const struct sockaddr_in6*)addr, addrlen);
#endif
	return ipv4_address_to_string(buffer, capacity, (const struct sockaddr_in*)addr, addrlen);
}
//---------------------------------------------------------------------------
// Callback handling parsing answers to queries sent
//---------------------------------------------------------------------------

// Callback handling parsing answers to queries sent
static int
query_callback(int sock, const struct sockaddr* from, size_t addrlen, mdns_entry_type_t entry,
               uint16_t query_id, uint16_t rtype, uint16_t rclass, uint32_t ttl, const void* data,
               size_t size, size_t name_offset, size_t name_length, size_t record_offset,
			   size_t record_length, void* user_data) {
	(void)sizeof(sock);
	(void)sizeof(query_id);
	(void)sizeof(name_length);
	(void)sizeof(user_data);
	mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer, sizeof(addrbuffer), from, addrlen);
	const char* entrytype = (entry == MDNS_ENTRYTYPE_ANSWER) ?
                                "answer" :
                                ((entry == MDNS_ENTRYTYPE_AUTHORITY) ? "authority" : "additional");
	mdns_string_t entrystr =
	    mdns_string_extract(data, size, &name_offset, entrybuffer, sizeof(entrybuffer));
	if (rtype == MDNS_RECORDTYPE_PTR) {
		mdns_string_t namestr = mdns_record_parse_ptr(data, size, record_offset, record_length,
		                                              namebuffer, sizeof(namebuffer));
		if (DEBUGGINGX(6)) debug("%.*s : %s %.*s PTR %.*s rclass 0x%x ttl %u length %d",
		       MDNS_STRING_FORMAT(fromaddrstr), entrytype, MDNS_STRING_FORMAT(entrystr),
		       MDNS_STRING_FORMAT(namestr), rclass, ttl, (int)record_length);
	} else if (rtype == MDNS_RECORDTYPE_SRV) {
		mdns_record_srv_t srv = mdns_record_parse_srv(data, size, record_offset, record_length,
		                                              namebuffer, sizeof(namebuffer));
		if (DEBUGGINGX(6)) debug("%.*s : %s %.*s SRV %.*s priority %d weight %d port %d",
		       MDNS_STRING_FORMAT(fromaddrstr), entrytype, MDNS_STRING_FORMAT(entrystr),
		       MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port);
	} else if (rtype == MDNS_RECORDTYPE_A) {
		struct sockaddr_in addr;
		mdns_record_parse_a(data, size, record_offset, record_length, &addr);
		mdns_string_t addrstr =
		    ipv4_address_to_string(namebuffer, sizeof(namebuffer), &addr, sizeof(addr));
		if (DEBUGGINGX(6)) debug("%.*s : %s %.*s A %.*s", MDNS_STRING_FORMAT(fromaddrstr), entrytype,
		       MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(addrstr));
#if __BORLANDC__ >= 0x720
	} else if (rtype == MDNS_RECORDTYPE_AAAA) {
		struct sockaddr_in6 addr;
		mdns_record_parse_aaaa(data, size, record_offset, record_length, &addr);
		mdns_string_t addrstr =
		    ipv6_address_to_string(namebuffer, sizeof(namebuffer), &addr, sizeof(addr));
		if (DEBUGGINGX(6)) debug("%.*s : %s %.*s AAAA %.*s", MDNS_STRING_FORMAT(fromaddrstr), entrytype,
		       MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(addrstr));
#endif
	} else if (rtype == MDNS_RECORDTYPE_TXT) {
		size_t parsed = mdns_record_parse_txt(data, size, record_offset, record_length, txtbuffer,
		                                      sizeof(txtbuffer) / sizeof(mdns_record_txt_t));
		for (size_t itxt = 0; itxt < parsed; ++itxt) {
			if (txtbuffer[itxt].value.length) {
				if (DEBUGGINGX(6)) debug("%.*s : %s %.*s TXT %.*s = %.*s", MDNS_STRING_FORMAT(fromaddrstr),
				       entrytype, MDNS_STRING_FORMAT(entrystr),
				       MDNS_STRING_FORMAT(txtbuffer[itxt].key),
				       MDNS_STRING_FORMAT(txtbuffer[itxt].value));
			} else {
				if (DEBUGGINGX(6)) debug("%.*s : %s %.*s TXT %.*s", MDNS_STRING_FORMAT(fromaddrstr), entrytype,
				       MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(txtbuffer[itxt].key));
			}
		}
	} else {
		if (DEBUGGINGX(6)) debug("%.*s : %s %.*s type %u rclass 0x%x ttl %u length %d",
		       MDNS_STRING_FORMAT(fromaddrstr), entrytype, MDNS_STRING_FORMAT(entrystr), rtype,
		       rclass, ttl, (int)record_length);
	}
	return 0;
}

//---------------------------------------------------------------------------
// Callback handling questions incoming on service sockets
// There can be three services handled by this callback
//---------------------------------------------------------------------------
static int
service_callback(int sock, const struct sockaddr* from, size_t addrlen, mdns_entry_type_t entry,
                 uint16_t query_id, uint16_t rtype, uint16_t rclass, uint32_t ttl, const void* data,
                 size_t size, size_t name_offset, size_t name_length, size_t record_offset,
                 size_t record_length, void* user_data) {
	(void)sizeof(ttl);
	if (entry != MDNS_ENTRYTYPE_QUESTION)
		return 0;

	const char dns_sd[] = "_services._dns-sd._udp.local.";
	service_t* service[3]; 	// Handle 3 services only RTCMaster_udp and RTCHost_udp and RTCMaster_tcp
	service[0] = &((service_t*)user_data)[0];
	int iargcnt = 1;
	service[1] = &((service_t*)user_data)[1];
	if (service[1]->port != 0) iargcnt = 2;		// two services if the second port is not 0
	service[2] = &((service_t*)user_data)[2];
	if (service[2]->port != 0) iargcnt = 3;		// three services if the third port is not 0

  for (int iDex = 0; iDex < iargcnt ; iDex++) {
	// addrbuffer contains dotted IP address of computer sending the Question
	mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer, sizeof(addrbuffer), from, addrlen);

	size_t offset = name_offset;
	mdns_string_t name = mdns_string_extract(data, size, &offset, namebuffer, sizeof(namebuffer));

	const char* record_name = 0;
	if (rtype == MDNS_RECORDTYPE_PTR)
		record_name = "PTR";
	else if (rtype == MDNS_RECORDTYPE_SRV)
		record_name = "SRV";
	else if (rtype == MDNS_RECORDTYPE_A)
		record_name = "A";
#if __BORLANDC__ >= 0x720
	else if (rtype == MDNS_RECORDTYPE_AAAA)
		record_name = "AAAA";
#endif
	else if (rtype == MDNS_RECORDTYPE_ANY)
		record_name = "ANY";
	else
		return 0;
	// On an active network, the next print can generate a lot of output
	if (DEBUGGINGX(8)) debug("Query %s %.*s", record_name, MDNS_STRING_FORMAT(name));

	if ((name.length == (sizeof(dns_sd) - 1)) &&
		(strncmp(name.str, dns_sd, sizeof(dns_sd) - 1) == 0)) {
		if ((rtype == MDNS_RECORDTYPE_PTR) || (rtype == MDNS_RECORDTYPE_ANY)) {
			// The PTR query was for the DNS-SD domain, send answer with a PTR record for the
			// service name we advertise, typically on the "<_service-name>._tcp.local." format

	
			// Answer PTR record reverse mapping "<_service-name>._tcp.local." to
			// "<hostname>.<_service-name>._tcp.local."
			// Replacing designated initializers which are not supported in C++
			//mdns_record_t answer = {
			//	.name = name, .type = MDNS_RECORDTYPE_PTR, .data.ptr.name = service[iDex]->service};
			mdns_record_t answer;
				answer.name = name; answer.type = MDNS_RECORDTYPE_PTR; answer.data.ptr.name = service[iDex]->service;

			// Send the answer, unicast or multicast depending on flag in query
			uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
			if (DEBUGGINGX(5)) debug("Query %s --> answer %.*s (%s)", record_name, MDNS_STRING_FORMAT(answer.data.ptr.name),
				   (unicast ? "unicast" : "multicast"));

			if (unicast) {
				mdns_query_answer_unicast(sock, from, addrlen, sendbuffer, sizeof(sendbuffer),
				                          query_id, rtype, name.str, name.length, answer, 0, 0, 0,
										  0);
			} else {
				mdns_query_answer_multicast(sock, sendbuffer, sizeof(sendbuffer), answer, 0, 0, 0,
				                            0);
			}
		}
	} else if ((name.length == service[iDex]->service.length) &&
			   (strncmp(name.str, service[iDex]->service.str, name.length) == 0)) {
		if ((rtype == MDNS_RECORDTYPE_PTR) || (rtype == MDNS_RECORDTYPE_ANY)) {
			// The PTR query was for our service (usually "<_service-name._tcp.local"), answer a PTR
			// record reverse mapping the queried service name to our service instance name
			// (typically on the "<hostname>.<_service-name>._tcp.local." format), and add
			// additional records containing the SRV record mapping the service instance name to our
			// qualified hostname (typically "<hostname>.local.") and port, as well as any IPv4/IPv6
			// address for the hostname as A/AAAA records, and two test TXT records

			// Answer PTR record reverse mapping "<_service-name>._tcp.local." to
			// "<hostname>.<_service-name>._tcp.local."
			mdns_record_t answer = service[iDex]->record_ptr;

			mdns_record_t additional[5] = {0};
			size_t additional_count = 0;
			
			if (DEBUGGINGX(7)) debug("service_callback : name.length %d  service[%d]->service.length %d : name.str %s   service[%d]->service.str %s",
				name.length, iDex,  service[iDex]->service.length, name.str, iDex, service[iDex]->service.str);

			// SRV record mapping "<hostname>.<_service-name>._tcp.local." to
			// "<hostname>.local." with port. Set weight & priority to 0.
			additional[additional_count++] = service[iDex]->record_srv;
			// A/AAAA records mapping "<hostname>.local." to IPv4/IPv6 addresses
			if (service[iDex]->address_ipv4.sin_family == AF_INET)
				additional[additional_count++] = service[iDex]->record_a;
#if __BORLANDC__ >= 0x720
			if (service[iDex]->address_ipv6.sin6_family == AF_INET6)
				additional[additional_count++] = service[iDex]->record_aaaa;
#endif
			// Add two test TXT records for our service instance name, will be coalesced into
			// one record with both key-value pair strings by the library
			additional[additional_count++] = service[iDex]->txt_record[0];
			additional[additional_count++] = service[iDex]->txt_record[1];

			// Send the answer, unicast or multicast depending on flag in query
			uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
			if (DEBUGGINGX(5)) debug("Query %s --> answer %.*s port %d (%s)", record_name,
				   MDNS_STRING_FORMAT(service[iDex]->record_ptr.data.ptr.name),
				   service[iDex]->port,
			       (unicast ? "unicast" : "multicast"));

			if (unicast) {
				mdns_query_answer_unicast(sock, from, addrlen, sendbuffer, sizeof(sendbuffer),
				                          query_id, rtype, name.str, name.length, answer, 0, 0,
				                          additional, additional_count);
			} else {
				mdns_query_answer_multicast(sock, sendbuffer, sizeof(sendbuffer), answer, 0, 0,
				                            additional, additional_count);
			}
		}
	} else if ((name.length == service[iDex]->service_instance.length) &&
			   (strncmp(name.str, service[iDex]->service_instance.str, name.length) == 0)) {
		if ((rtype == MDNS_RECORDTYPE_SRV) || (rtype == MDNS_RECORDTYPE_ANY)) {
			// The SRV query was for our service instance (usually
			// "<hostname>.<_service-name._tcp.local"), answer a SRV record mapping the service
			// instance name to our qualified hostname (typically "<hostname>.local.") and port, as
			// well as any IPv4/IPv6 address for the hostname as A/AAAA records, and two test TXT
			// records

			// Answer PTR record reverse mapping "<_service-name>._tcp.local." to
			// "<hostname>.<_service-name>._tcp.local."
			mdns_record_t answer = service[iDex]->record_srv;

			mdns_record_t additional[5] = {0};
			size_t additional_count = 0;
			// A/AAAA records mapping "<hostname>.local." to IPv4/IPv6 addresses
			if (service[iDex]->address_ipv4.sin_family == AF_INET)
				additional[additional_count++] = service[iDex]->record_a;
#if __BORLANDC__ >= 0x720
			if (service[iDex]->address_ipv6.sin6_family == AF_INET6)
				additional[additional_count++] = service[iDex]->record_aaaa;
#endif
			// Add two test TXT records for our service instance name, will be coalesced into
			// one record with both key-value pair strings by the library
			additional[additional_count++] = service[iDex]->txt_record[0];
			additional[additional_count++] = service[iDex]->txt_record[1];

			// Send the answer, unicast or multicast depending on flag in query
			uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
			if (DEBUGGINGX(5)) debug("Query %s --> answer %.*s port %d (%s)", record_name,
				   MDNS_STRING_FORMAT(service[iDex]->record_srv.data.srv.name), service[iDex]->port,
			       (unicast ? "unicast" : "multicast"));

			if (unicast) {
				mdns_query_answer_unicast(sock, from, addrlen, sendbuffer, sizeof(sendbuffer),
				                          query_id, rtype, name.str, name.length, answer, 0, 0,
				                          additional, additional_count);
			} else {
				mdns_query_answer_multicast(sock, sendbuffer, sizeof(sendbuffer), answer, 0, 0,
				                            additional, additional_count);
			}
		}
	} else if ((name.length == service[iDex]->hostname_qualified.length) &&
			   (strncmp(name.str, service[iDex]->hostname_qualified.str, name.length) == 0)) {
		if (((rtype == MDNS_RECORDTYPE_A) || (rtype == MDNS_RECORDTYPE_ANY)) &&
			(service[iDex]->address_ipv4.sin_family == AF_INET)) {
			// The A query was for our qualified hostname (typically "<hostname>.local.") and we
			// have an IPv4 address, answer with an A record mappiing the hostname to an IPv4
			// address, as well as any IPv6 address for the hostname, and two test TXT records

			// Answer A records mapping "<hostname>.local." to IPv4 address
			mdns_record_t answer = service[iDex]->record_a;

			mdns_record_t additional[5] = {0};
			size_t additional_count = 0;
#if __BORLANDC__ >= 0x720
			// AAAA record mapping "<hostname>.local." to IPv6 addresses
			if (service[iDex]->address_ipv6.sin6_family == AF_INET6)
				additional[additional_count++] = service[iDex]->record_aaaa;
#endif

			// Add two test TXT records for our service instance name, will be coalesced into
			// one record with both key-value pair strings by the library
			additional[additional_count++] = service[iDex]->txt_record[0];
			additional[additional_count++] = service[iDex]->txt_record[1];

			// Send the answer, unicast or multicast depending on flag in query
			uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
			mdns_string_t addrstr = ip_address_to_string(
				addrbuffer, sizeof(addrbuffer), (struct sockaddr*)&service[iDex]->record_a.data.a.addr,
				sizeof(service[iDex]->record_a.data.a.addr));
			if (DEBUGGINGX(5)) debug("Query %s --> answer %.*s IPv4 %.*s (%s)", record_name, MDNS_STRING_FORMAT(service[iDex]->record_a.name),
			       MDNS_STRING_FORMAT(addrstr), (unicast ? "unicast" : "multicast"));

			if (unicast) {
				mdns_query_answer_unicast(sock, from, addrlen, sendbuffer, sizeof(sendbuffer),
				                          query_id, rtype, name.str, name.length, answer, 0, 0,
				                          additional, additional_count);
			} else {
				mdns_query_answer_multicast(sock, sendbuffer, sizeof(sendbuffer), answer, 0, 0,
				                            additional, additional_count);
			}
		}
#if __BORLANDC__ >= 0x720
		else if (((rtype == MDNS_RECORDTYPE_AAAA) || (rtype == MDNS_RECORDTYPE_ANY)) &&
				   (service[iDex]->address_ipv6.sin6_family == AF_INET6)) {
			// The AAAA query was for our qualified hostname (typically "<hostname>.local.") and we
			// have an IPv6 address, answer with an AAAA record mappiing the hostname to an IPv6
			// address, as well as any IPv4 address for the hostname, and two test TXT records

			// Answer AAAA records mapping "<hostname>.local." to IPv6 address
			mdns_record_t answer = service[iDex]->record_aaaa;

			mdns_record_t additional[5] = {0};
			size_t additional_count = 0;

			// A record mapping "<hostname>.local." to IPv4 addresses
			if (service[iDex]->address_ipv4.sin_family == AF_INET)
				additional[additional_count++] = service[iDex]->record_a;

			// Add two test TXT records for our service instance name, will be coalesced into
			// one record with both key-value pair strings by the library
			additional[additional_count++] = service[iDex]->txt_record[0];
			additional[additional_count++] = service[iDex]->txt_record[1];

			// Send the answer, unicast or multicast depending on flag in query
			uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
			mdns_string_t addrstr =
			    ip_address_to_string(addrbuffer, sizeof(addrbuffer),
									 (struct sockaddr*)&service[iDex]->record_aaaa.data.aaaa.addr,
									 sizeof(service[iDex]->record_aaaa.data.aaaa.addr));
			if (DEBUGGINGX(5)) debug("Query %s --> answer %.*s IPv6 %.*s (%s)", record_name,
				   MDNS_STRING_FORMAT(service[iDex]->record_aaaa.name), MDNS_STRING_FORMAT(addrstr),
			       (unicast ? "unicast" : "multicast"));

			if (unicast) {
				mdns_query_answer_unicast(sock, from, addrlen, sendbuffer, sizeof(sendbuffer),
				                          query_id, rtype, name.str, name.length, answer, 0, 0,
				                          additional, additional_count);
			} else {
				mdns_query_answer_multicast(sock, sendbuffer, sizeof(sendbuffer), answer, 0, 0,
				                            additional, additional_count);
			}
		}
#endif
	}
  }
return 0;
}

//---------------------------------------------------------------------------
// Open sockets for sending one-shot multicast queries from an ephemeral port
//---------------------------------------------------------------------------
static int
open_client_sockets(int* sockets, int max_sockets, int port) {
	// When sending, each socket can only send to one interface (IP address)
	// Thus we need to open one socket for each interface and address family
	int num_sockets = 0;

#define DOITTHEORIGINALWAY true
// Set to true to use the original open_client_sockets code.
#if DOITTHEORIGINALWAY
#if __BORLANDC__ >= 0x720
    //
    // CB10.1 Version
	//
        has_ipv6 = 0;
        has_ipv4 = 0;
		struct sockaddr_in saddr;
        memset(&saddr, 0, sizeof(struct sockaddr_in));

		saddr.sin_family = AF_INET;
		saddr.sin_port = htons((unsigned short)port);
		//saddr.sin_addr.s_addr = inet_addr("192.168.1.100"); // MCD DEBUG
		saddr.sin_addr.s_addr = MyHostSaddr;

		service_address_ipv4 = saddr;	// load the IPv4 into the service address
		num_sockets++;
		has_ipv4 = 1;
		char buffer[128];
		mdns_string_t addr = ipv4_address_to_string(buffer, sizeof(buffer), &saddr,
										sizeof(struct sockaddr_in));
		if (DEBUGGING) debug("open_client_sockets: Local IPv4 address: %.*s", MDNS_STRING_FORMAT(addr));

#else
    //
    //	BCB4.0 Version
    //
        has_ipv4 = 0;
		struct sockaddr_in saddr;
        memset(&saddr, 0, sizeof(struct sockaddr_in));

		saddr.sin_family = AF_INET;
		saddr.sin_port = htons((unsigned short)port);
		//saddr.sin_addr.s_addr = inet_addr("192.168.1.100"); // MCD DEBUG
		saddr.sin_addr.s_addr = MyHostSaddr;
        //if (DEBUGGING) debug("open_client_sockets - MyHostSaddr %08X", MyHostSaddr);
		service_address_ipv4 = saddr;	// load the IPv4 into the service address
		num_sockets++;
		has_ipv4 = 1;
		char buffer[128];
		mdns_string_t addr = ipv4_address_to_string(buffer, sizeof(buffer), &saddr,
										sizeof(struct sockaddr_in));
		if (DEBUGGING) debug("open_client_sockets: Local IPv4 address: %.*s", MDNS_STRING_FORMAT(addr));

#endif
	if (DEBUGGING) debug("Opened %d client sockets", num_sockets);
	return num_sockets;


#else  // #if not DOITTHEORIGINALWAY // use newer code
not used
#if __BORLANDC__ >= 0x720
    //
    // CB10.1 Version
	// CB10.1 supports GetAdaptersAddresses
    //
	IP_ADAPTER_ADDRESSES* adapter_address = 0;
	ULONG address_size = 8000;
	unsigned int ret;
	unsigned int num_retries = 4;
	do {
		adapter_address = (IP_ADAPTER_ADDRESSES*)malloc(address_size);
		ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST, 0,
		                           adapter_address, &address_size);
		if (ret == ERROR_BUFFER_OVERFLOW) {
			free(adapter_address);
			adapter_address = 0;
			address_size *= 2;
		} else {
			break;
		}
	} while (num_retries-- > 0);

	if (!adapter_address || (ret != NO_ERROR)) {
		free(adapter_address);
		if (DEBUGGING) debug("Failed to get network adapter addresses");
		return num_sockets;
	}

	int first_ipv4 = 1;
	int first_ipv6 = 1;
	for (PIP_ADAPTER_ADDRESSES adapter = adapter_address; adapter; adapter = adapter->Next) {
		if (adapter->TunnelType == TUNNEL_TYPE_TEREDO)
			continue;
		if (adapter->OperStatus != IfOperStatusUp)
			continue;

		for (IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress; unicast;
		     unicast = unicast->Next) {
			if (unicast->Address.lpSockaddr->sa_family == AF_INET) {
				struct sockaddr_in* saddr = (struct sockaddr_in*)unicast->Address.lpSockaddr;
				if ((saddr->sin_addr.S_un.S_un_b.s_b1 != 127) ||
				    (saddr->sin_addr.S_un.S_un_b.s_b2 != 0) ||
				    (saddr->sin_addr.S_un.S_un_b.s_b3 != 0) ||
				    (saddr->sin_addr.S_un.S_un_b.s_b4 != 1)) {
					int log_addr = 0;
					if (first_ipv4) {
						service_address_ipv4 = *saddr;	// load the first found IPv4 into the service address - not really correct way to do it
						first_ipv4 = 0;
						log_addr = 1;
					}
					has_ipv4 = 1;
					if (num_sockets < max_sockets) {
						saddr->sin_port = htons((unsigned short)port);
						int sock = mdns_socket_open_ipv4(saddr);
						if (sock >= 0) {
							sockets[num_sockets++] = sock;
							log_addr = 1;
						} else {
							log_addr = 0;
						}
					}
					if (log_addr) {
						char buffer[128];
						mdns_string_t addr = ipv4_address_to_string(buffer, sizeof(buffer), saddr,
						                                            sizeof(struct sockaddr_in));
not used				if (DEBUGGING) debug("Local IPv4 address: %.*s", MDNS_STRING_FORMAT(addr));
					}
				}
			} else if (unicast->Address.lpSockaddr->sa_family == AF_INET6) {
				struct sockaddr_in6* saddr = (struct sockaddr_in6*)unicast->Address.lpSockaddr;
				static const unsigned char localhost[] = {0, 0, 0, 0, 0, 0, 0, 0,
				                                          0, 0, 0, 0, 0, 0, 0, 1};
				static const unsigned char localhost_mapped[] = {0, 0, 0,    0,    0,    0, 0, 0,
				                                                 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1};
				if ((unicast->DadState == NldsPreferred) &&
				    memcmp(saddr->sin6_addr.s6_addr, localhost, 16) &&
				    memcmp(saddr->sin6_addr.s6_addr, localhost_mapped, 16)) {
					int log_addr = 0;
					if (first_ipv6) {
						service_address_ipv6 = *saddr;	// load the first found IPv6 into the service address - not really correct way to do it
						first_ipv6 = 0;
						log_addr = 1;
					}
					has_ipv6 = 1;
					if (num_sockets < max_sockets) {
						saddr->sin6_port = htons((unsigned short)port);
						int sock = mdns_socket_open_ipv6(saddr);
						if (sock >= 0) {
							sockets[num_sockets++] = sock;
							log_addr = 1;
						} else {
							log_addr = 0;
						}
					}
					if (log_addr) {
						char buffer[128];
						mdns_string_t addr = ipv6_address_to_string(buffer, sizeof(buffer), saddr,
						                                            sizeof(struct sockaddr_in6));
not used						if (DEBUGGING) debug("Local IPv6 address: %.*s", MDNS_STRING_FORMAT(addr));
					}
				}
			}
		}
	}

	free(adapter_address);
#else
not used
    //
    //	BCB4.0 Version
    //
	char buf[128];
	int ret = gethostname(buf, 128);
	struct hostent * adapter_address;
	
	int first_ipv4 = 1;
	if (ret == 0) {
		adapter_address = gethostbyname(buf);
		DWORD dwError;
		int i = 0;
		char **pAlias;
		int log_addr = 0;
		struct in_addr addr;

		if (adapter_address == NULL) {
			dwError = WSAGetLastError();
			if (dwError != 0) {
				if (dwError == WSAHOST_NOT_FOUND) {
					if (DEBUGGING) debug("Host not found");
					return 1;
					} else if (dwError == WSANO_DATA) {
						if (DEBUGGING) debug("No data record found");
						return 1;
							} else {
							if (DEBUGGING) debug("gethostbyname failed with error: %ld", dwError);
							return 1;
							}
				}
			} else {
			
			if (DEBUGGING) debug("gethostbyname returned:");
			if (DEBUGGING) debug("  Official name: %s", adapter_address->h_name);
			for (pAlias = adapter_address->h_aliases; *pAlias != 0; pAlias++) {
				if (DEBUGGING) debug("  Alternate name #%d: %s", ++i, *pAlias);
				}
			if (DEBUGGING) debug("  Address type: %s", (adapter_address->h_addrtype == AF_INET)? "AF_INET" : "AF_NETBIOS" );
			if (DEBUGGING) debug("  Address length: %d", adapter_address->h_length);

			i = 0;
			if (adapter_address->h_addrtype == AF_INET) 	{
				while (adapter_address->h_addr_list[i] != 0) {
					addr.s_addr = *(u_long *) adapter_address->h_addr_list[i++];
					if (DEBUGGING) debug("  IP Address #%d: %s", i, inet_ntoa(addr));

// CODE MOVED HERE
		struct sockaddr_in saddr;
        memset(&saddr, 0, sizeof(struct sockaddr_in));

		saddr.sin_family = AF_INET;
		saddr.sin_port = htons((unsigned short)port);
		//saddr.sin_addr.s_addr = addr.s_addr;
		saddr.sin_addr.s_addr = MyHostIP;        // MCD DEBUG

		if (first_ipv4) {
			service_address_ipv4 = saddr;	// load the LAST found IPv4 into the service address - not really correct way to do it
			first_ipv4 = 0;
			log_addr = 1;
			}

		has_ipv4 = 1;
        // In the current implementation, the next compare is never true
		if (num_sockets < max_sockets) {
			int sock = mdns_socket_open_ipv4(&saddr);
			if (sock >= 0) {
				sockets[num_sockets++] = sock;
				log_addr = 1;
				} else {
				log_addr = 0;
				}
			}

		if (log_addr) {
			char buffer[128];
			mdns_string_t addr = ipv4_address_to_string(buffer, sizeof(buffer), &saddr,
										sizeof(struct sockaddr_in));
not used	if (DEBUGGING) debug("Local IPv4 address: %.*s", MDNS_STRING_FORMAT(addr));
			}




// CODE MOVED HERE

					}
				} else if (adapter_address->h_addrtype == AF_NETBIOS) {
					if (DEBUGGING) debug("NETBIOS address was returned");
					}   
			}
#ifdef ORIGINALCODEMOVEUPTHERE
not used
		struct sockaddr_in saddr;
        memset(&saddr, 0, sizeof(struct sockaddr_in));

		saddr.sin_family = AF_INET;
		saddr.sin_port = htons((unsigned short)port);
		saddr.sin_addr.s_addr = addr.s_addr;

		if (first_ipv4) {
			service_address_ipv4 = saddr;	// load the LAST found IPv4 into the service address - not really correct way to do it
			first_ipv4 = 0;
			log_addr = 1;
			}

		has_ipv4 = 1;
        // In the current implementation, the next compare is never true
		if (num_sockets < max_sockets) {
			int sock = mdns_socket_open_ipv4(&saddr);
			if (sock >= 0) {
				sockets[num_sockets++] = sock;
				log_addr = 1;
				} else {
				log_addr = 0;
				}
			}

		if (log_addr) {
			char buffer[128];
			mdns_string_t addr = ipv4_address_to_string(buffer, sizeof(buffer), &saddr,
										sizeof(struct sockaddr_in));
not used	if (DEBUGGING) debug("Local IPv4 address: %.*s", MDNS_STRING_FORMAT(addr));
			}
#endif
		}
#endif
	if (DEBUGGING) debug("Opened %d client sockets", num_sockets);
	return num_sockets;
#endif
}
//---------------------------------------------------------------------------
// Open sockets to listen to incoming mDNS queries on port 5353
//---------------------------------------------------------------------------

static int
open_service_sockets(int* sockets, int max_sockets) {
	// When recieving, each socket can recieve data from all network interfaces
	// Thus we only need to open one socket for each address family
    //
    // CB 10.1 supports ipv6 as well as ipv4, so two sockets are opened.
	int num_sockets = 0;
	// Call the client socket function to enumerate and get local addresses,
	// but not open the actual sockets
	open_client_sockets(0, 0, 0);
	if (num_sockets < max_sockets) {
		struct sockaddr_in sock_addr;
		memset(&sock_addr, 0, sizeof(struct sockaddr_in));
		sock_addr.sin_family = AF_INET;
		//sock_addr.sin_addr = inaddr_any;			//  this would not compile, used the alternate code just below
		//sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
		sock_addr.sin_addr.s_addr = MyHostSaddr;
		sock_addr.sin_port = htons(MDNS_PORT);
        // open the ipv4 socket
		int sock = mdns_socket_open_ipv4(&sock_addr);
		if (sock >= 0)
			sockets[num_sockets++] = sock;
	}
#if __BORLANDC__ >= 0x720
	if (num_sockets < max_sockets) {
		struct sockaddr_in6 sock_addr;
		memset(&sock_addr, 0, sizeof(struct sockaddr_in6));
		sock_addr.sin6_family = AF_INET6;
		sock_addr.sin6_addr = in6addr_any;
		sock_addr.sin6_port = htons(MDNS_PORT);
		// open the ipv6 socket
		int sock = mdns_socket_open_ipv6(&sock_addr);
		if (sock >= 0)
			sockets[num_sockets++] = sock;
	}
#endif
#if __BORLANDC__ >= 0x720
	if (DEBUGGING) debug("Opened %d service socket%s (ipv4 and ipv6)", num_sockets, num_sockets ? "s" : "");
#else
	if (DEBUGGING) debug("Opened %d service socket%s (ipv4)", num_sockets, num_sockets ? "s" : "");
#endif
	return num_sockets;
}

//---------------------------------------------------------------------------
// Send a mDNS query - not used by RTC (Uses mDNSThread instead
//---------------------------------------------------------------------------

static int
send_mdns_query(const char* service, int record) {
	int sockets[32];
	int query_id[32];
	int num_sockets = open_client_sockets(sockets, sizeof(sockets) / sizeof(sockets[0]), 0);
	if (num_sockets <= 0) {
		if (DEBUGGING) debug("Failed to open any client sockets");
		return -1;
	}
	if (DEBUGGING) debug("Opened %d client socket%s for mDNS query", num_sockets, num_sockets > 1 ? "s" : "");
    if (DEBUGGING) debug("Sending mDNS Query discovery");
	size_t capacity = 2048;
	void* buffer = malloc(capacity);
	void* user_data = 0;
	//size_t records;
	const char* record_name = "PTR";
	if (record == MDNS_RECORDTYPE_SRV)
		record_name = "SRV";
	else if (record == MDNS_RECORDTYPE_A)
		record_name = "A";
	else if (record == MDNS_RECORDTYPE_AAAA)
		record_name = "AAAA";
	else
		record = MDNS_RECORDTYPE_PTR;
	if (DEBUGGING) debug("Sending mDNS query: %s %s", service, record_name);
	for (int isock = 0; isock < num_sockets; ++isock) {
		query_id[isock] =
			mdns_query_send(sockets[isock], record, service, strlen(service), buffer, capacity, 0);
		if (query_id[isock] < 0)
			if (DEBUGGING) debug("Failed to send mDNS query: %s", strerror(errno));
		Sleep(100);	// needed - yes - Query fails with 50ms delay, works with 100ms delay
	}

	// This is a simple implementation that loops for 5 seconds or as long as we get replies
	int res;
	if (DEBUGGING) debug("Reading mDNS query replies");
	do {
		if (mDNSTerminate) break;				// terminate on request
		struct timeval timeout;
		timeout.tv_sec = 5;
		timeout.tv_usec = 0;
		int nfds = 0;
		fd_set readfs;
		FD_ZERO(&readfs);
		for (int isock = 0; isock < num_sockets; ++isock) {
			if (sockets[isock] >= nfds)
				nfds = sockets[isock] + 1;
			FD_SET(sockets[isock], &readfs);
		}
		//records = 0;
		res = select(nfds, &readfs, 0, 0, &timeout);
		if (mDNSTerminate) break; 				// terminate on request
		if (res > 0) {
			for (int isock = 0; isock < num_sockets; ++isock) {
				if (FD_ISSET(sockets[isock], &readfs)) {
					//records +=
					mdns_query_recv(sockets[isock], buffer, capacity, query_callback,
											   user_data, query_id[isock]);
				}
				FD_SET(sockets[isock], &readfs);
			}
		}
	} while (res > 0);

	free(buffer);
	for (int isock = 0; isock < num_sockets; ++isock)
		mdns_socket_close(sockets[isock]);
	if (DEBUGGING) debug("Closed socket%s", num_sockets > 1 ? "s" : "");
	return 0;
}

//---------------------------------------------------------------------------
// Provide a mDNS service responder, answering incoming DNS-SD and mDNS queries
//---------------------------------------------------------------------------
static int
service_mdns(const char* hostname, const char* service_name[3], int service_port[3], int iargcnt) {
	assert(iargcnt >= 1 && iargcnt <= 3);
	int sockets[32];
	int num_sockets = open_service_sockets(sockets, sizeof(sockets) / sizeof(sockets[0]));
	if (num_sockets <= 0) {
		if (DEBUGGING) debug("Failed to open any service sockets");
		return -1;
		}
#if __BORLANDC__ >= 0x720
	if (DEBUGGING) debug("Opened %d socket%s for mDNS service (ipv4 and ipv6)", num_sockets, num_sockets == 1 ? "" : "s");
#else
	if (DEBUGGING) debug("Opened %d socket%s for mDNS service (ipv4)", num_sockets, num_sockets == 1 ? "" : "s");
#endif
//
//  I thought about removing the dynamic allocation and using the stack but malloc/free worked ok
//
	size_t capacity = 2048;
    // following are dynamically allocated
	void* buffer = malloc(capacity);
//	char buffer[2048];

	service_t service[3] = {NULL, NULL, NULL};
	mdns_string_t * service_string[3] = {NULL, NULL, NULL};
	mdns_string_t * hostname_string[3] = {NULL, NULL, NULL};
	mdns_string_t * service_instance_string[3] = {NULL, NULL, NULL};
	mdns_string_t * hostname_qualified_string[3] = {NULL, NULL, NULL};
	char * service_name_buffer[3] = {NULL, NULL, NULL};
//	char service_name_buffer[3][2048] = {"", "", ""};

	// following are statically allocated
	char service_instance_buffer[3][256] = {"", "", ""};
	char qualified_hostname_buffer[3][256] = {"", "", ""};

  for (int iDex = 0; iDex < iargcnt; iDex++) {
	size_t service_name_length = strlen(service_name[iDex]);
	if (!service_name_length) {
		if (DEBUGGING) debug("Invalid service name");
		return -1;
		}
	if (DEBUGGINGX(5)) debug("service_mdns() index %d", iDex);

	service_name_buffer[iDex] = (char *)malloc(service_name_length + 2);
    	assert(service_name_buffer[iDex]);	// make sure the allocation worked

	memcpy(service_name_buffer[iDex], service_name[iDex], service_name_length);
	if (service_name_buffer[iDex][service_name_length - 1] != '.')
		service_name_buffer[iDex][service_name_length++] = '.';
	service_name_buffer[iDex][service_name_length] = 0;
	service_name[iDex] = service_name_buffer[iDex];

	if (DEBUGGING) debug("Service mDNS: %s:%d", service_name[iDex], service_port[iDex]);
	if (DEBUGGING) debug("Hostname: %s", hostname);

	// Replacing designated initializers which are not supported in C++
	//service_string[iDex] = &(mdns_string_t){service_name[iDex], strlen(service_name[iDex])};
	//hostname_string[iDex] = &(mdns_string_t){hostname, strlen(hostname)};
	mdns_string_t x1 = {service_name[iDex], strlen(service_name[iDex])};
	service_string[iDex] = &x1;

	mdns_string_t x2 = {hostname, strlen(hostname)};
	hostname_string[iDex] = &x2;

	// Build the service instance "<hostname>.<_service-name>._tcp.local." string
	
	snprintf(service_instance_buffer[iDex], sizeof(service_instance_buffer) - 1, "%.*s.%.*s",
			 MDNS_STRING_PTR_FORMAT(hostname_string[iDex]), MDNS_STRING_PTR_FORMAT(service_string[iDex]));
	// Replacing designated initializers which are not supported in C++
	//service_instance_string[iDex] =
	//	&(mdns_string_t){service_instance_buffer[iDex], strlen(service_instance_buffer[iDex])};
	mdns_string_t x3 = {service_instance_buffer[iDex], strlen(service_instance_buffer[iDex])};
	service_instance_string[iDex] = &x3;

	// Build the "<hostname>.local." string
	snprintf(qualified_hostname_buffer[iDex], sizeof(qualified_hostname_buffer) - 1, "%.*s.local.",
			 MDNS_STRING_PTR_FORMAT(hostname_string[iDex]));
	// Replacing designated initializers which are not supported in C++
	//hostname_qualified_string[iDex] =
	//	&(mdns_string_t){qualified_hostname_buffer[iDex], strlen(qualified_hostname_buffer[iDex])};
	mdns_string_t x4 = {qualified_hostname_buffer[iDex], strlen(qualified_hostname_buffer[iDex])};
	hostname_qualified_string[iDex] = &x4;

	service[iDex].service = *service_string[iDex];
	service[iDex].hostname = *hostname_string[iDex];
	service[iDex].service_instance = *service_instance_string[iDex];
	service[iDex].hostname_qualified = *hostname_qualified_string[iDex];
	service[iDex].address_ipv4 = service_address_ipv4;
	#if __BORLANDC__ >= 0x720
	service[iDex].address_ipv6 = service_address_ipv6;
	#endif
	service[iDex].port = service_port[iDex];
	
	// Setup our mDNS records

	// PTR record reverse mapping "<_service-name>._tcp.local." to
	// "<hostname>.<_service-name>._tcp.local."
	//service[iDex].record_ptr = (mdns_record_t){.name = service[iDex].service,
	//									 .type = MDNS_RECORDTYPE_PTR,
	//									 .data.ptr.name = service[iDex].service_instance};
	// Replacing designated initializers which are not supported in C++
	mdns_record_t t1;
		t1.name = service[iDex].service;
		t1.type = MDNS_RECORDTYPE_PTR;
		t1.data.ptr.name = service[iDex].service_instance;
	service[iDex].record_ptr = t1;
	// SRV record mapping "<hostname>.<_service-name>._tcp.local." to
	// "<hostname>.local." with port. Set weight & priority to 0.
    //	service[iDex].record_srv = (mdns_record_t){.name = service[iDex].service_instance,
    //	                                     .type = MDNS_RECORDTYPE_SRV,
    //										 .data.srv.name = service[iDex].hostname_qualified,
    //										 .data.srv.port = service[iDex].port,
    //	                                     .data.srv.priority = 0,
    //	                                     .data.srv.weight = 0};
	// Replacing designated initializers which are not supported in C++
	mdns_record_t t2;
		t2.name = service[iDex].service_instance;
		t2.type = MDNS_RECORDTYPE_SRV;
		t2.data.srv.name = service[iDex].hostname_qualified;
		t2.data.srv.port = service[iDex].port;
		t2.data.srv.priority = 0;
		t2.data.srv.weight = 0;
	service[iDex].record_srv = t2;
    //
    //	// A/AAAA records mapping "<hostname>.local." to IPv4/IPv6 addresses
    //	service[iDex].record_a = (mdns_record_t){.name = service[iDex].hostname_qualified,
    //	                                   .type = MDNS_RECORDTYPE_A,
    //									   .data.a.addr = service[iDex].address_ipv4};
	// A/AAAA records mapping "<hostname>.local." to IPv4/IPv6 addresses
	// Replacing designated initializers which are not supported in C++
	mdns_record_t t3;
		t3.name = service[iDex].hostname_qualified;
		t3.type = MDNS_RECORDTYPE_A;
		//t3.data.a.addr.sin_addr.S_un.S_addr = 0x01020304L;	// DEBUG ONLY to see if I can change the A record field - this does change it.
		t3.data.a.addr = service[iDex].address_ipv4;	// original line can put the wrong IPv4 address into this field
														// on computers with multiple Ethernet ports (it always selects the first port found)
	service[iDex].record_a = t3;

	#if __BORLANDC__ >= 0x720
    //
	//	service[iDex].record_aaaa = (mdns_record_t){.name = service[iDex].hostname_qualified,
	//	                                      .type = MDNS_RECORDTYPE_AAAA,
	//										  .data.aaaa.addr = service[iDex].address_ipv6};
	// Replacing designated initializers which are not supported in C++
	mdns_record_t t4;
		t4.name = service[iDex].hostname_qualified;
		t4.type = MDNS_RECORDTYPE_AAAA;
		t4.data.aaaa.addr = service[iDex].address_ipv6;	// original line can put the wrong IPv6 address into this field
														// on computers with multiple Ethernet ports (it always selects the first port found)
	service[iDex].record_aaaa = t4;
	#endif
    //	// Add two test TXT records for our service instance name, will be coalesced into
    //	// one record with both key-value pair strings by the library
    //	service[iDex].txt_record[0] = (mdns_record_t){.name = service[iDex].service_instance,
    //	                                        .type = MDNS_RECORDTYPE_TXT,
	//											.data.txt.key = {MDNS_STRING_CONST("Web Site")},
    //											.data.txt.value = {MDNS_STRING_CONST("http://www.silogic.com/trains/WiFi.html")}};
	// Add two test TXT records for our service instance name, will be coalesced into
	// one record with both key-value pair strings by the library
	// Replacing designated initializers which are not supported in C++
	mdns_record_t t5;
		t5.name = service[iDex].service_instance;
		t5.type = MDNS_RECORDTYPE_TXT;
		mdns_string_t ww1 =  {MDNS_STRING_CONST("Web Site")};
		t5.data.txt.key = ww1;
		mdns_string_t ww2 =  {MDNS_STRING_CONST("http://www.silogic.com/trains/WiFi.html")};
		t5.data.txt.value = ww2;
	service[iDex].txt_record[0] = t5;
    //	service[iDex].txt_record[1] = (mdns_record_t){.name = service[iDex].service_instance,
    //	                                        .type = MDNS_RECORDTYPE_TXT,
    //											.data.txt.key = {MDNS_STRING_CONST("Author")},
    //											.data.txt.value = {MDNS_STRING_CONST("Mark C. DiVecchio")}};
	// Replacing designated initializers which are not supported in C++
	mdns_record_t t6;
		t6.name = service[iDex].service_instance;
		t6.type = MDNS_RECORDTYPE_TXT;
		mdns_string_t yy1 =  {MDNS_STRING_CONST("Author")};
		t6.data.txt.key = yy1;
		mdns_string_t yy2 =  {MDNS_STRING_CONST("Mark C. DiVecchio")};
		t6.data.txt.value = yy2;
	service[iDex].txt_record[1] = t6;

	if (DEBUGGINGX(5)) debug("service_mdns() : service[%d].service.length %d : service[%d].service.str %s",
		iDex,  service[iDex].service.length, iDex, service[iDex].service.str);

	if (DEBUGGING) debug("Send an announcement on startup of service");

	// Send an announcement on startup of service
	{
    mdns_record_t additional[5] = {0};
    size_t additional_count = 0;
    additional[additional_count++] = service[iDex].record_srv;
    if (service[iDex].address_ipv4.sin_family == AF_INET)
        additional[additional_count++] = service[iDex].record_a;
    #if __BORLANDC__ >= 0x720
    if (service[iDex].address_ipv6.sin6_family == AF_INET6)
		additional[additional_count++] = service[iDex].record_aaaa;
    #endif
    additional[additional_count++] = service[iDex].txt_record[0];
    additional[additional_count++] = service[iDex].txt_record[1];

    for (int isock = 0; isock < num_sockets; ++isock)
        mdns_announce_multicast(sockets[isock], buffer, capacity, service[iDex].record_ptr, 0, 0,
                                additional, additional_count);
	}
  }

	int res;
	// This is a crude implementation that checks for incoming queries
	while (1) {
		if (mDNSTerminate) {
			break;				// terminate on request
			}
		struct timeval timeout;
		timeout.tv_sec = 5;
		timeout.tv_usec = 0;
		int nfds = 0;
		fd_set readfs;
		FD_ZERO(&readfs);
		for (int isock = 0; isock < num_sockets; ++isock) {
			if (sockets[isock] >= nfds)
				nfds = sockets[isock] + 1;
			FD_SET(sockets[isock], &readfs);
		}

        res = select(nfds, &readfs, 0, 0, &timeout);
		if (mDNSTerminate) {
			break;				// terminate on request
			}
		if ( res > 0) {
			for (int isock = 0; isock < num_sockets; ++isock) {
				if (FD_ISSET(sockets[isock], &readfs)) {
					mdns_socket_listen(sockets[isock], buffer, capacity, service_callback,
						   service);		// changed to handle more than one service
					}
				FD_SET(sockets[isock], &readfs);
			}
		} else {
        continue;
        }
	}

	if (DEBUGGING) debug("Send a goodbye on end of service");

	for (int iDex = 0 ; iDex < iargcnt ; iDex++) {
		mdns_record_t additional[5] = {0};
		size_t additional_count = 0;
		additional[additional_count++] = service[iDex].record_srv;
		if (service[iDex].address_ipv4.sin_family == AF_INET)
			additional[additional_count++] = service[iDex].record_a;
		#if __BORLANDC__ >= 0x720
		if (service[iDex].address_ipv6.sin6_family == AF_INET6)
			additional[additional_count++] = service[iDex].record_aaaa;
		#endif
		additional[additional_count++] = service[iDex].txt_record[0];
		additional[additional_count++] = service[iDex].txt_record[1];

		for (int isock = 0; isock < num_sockets; ++isock)
			mdns_goodbye_multicast(sockets[isock], buffer, capacity, service[iDex].record_ptr, 0, 0,
									additional, additional_count);
	}
	if (DEBUGGING) {
		debug("Closing mDNS Service socket%s", num_sockets ? "s" : "");
		}
    //#ifdef SKIPTHIS
    //
    // Free malloc'ed memory
    //
	assert(buffer);
	if (buffer) free(buffer);

	for (int iDex = 0; iDex < iargcnt; iDex++) {
		assert(service_name_buffer[iDex]);
		if (service_name_buffer[iDex] != NULL) free(service_name_buffer[iDex]);
		}
    //#endif

	// close all sockets
	for (int isock = 0; isock < num_sockets; ++isock)
		mdns_socket_close(sockets[isock]);
	if (DEBUGGING) {
		debug("Closed mDNS Service socket%s", num_sockets ? "s" : "");
		}
	// only way here is if terminating
	return 0;
}


#ifdef __cplusplus
}
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//   Important: Methods and properties of objects in VCL can only be
//   used in a method called using Synchronize, for example:
//
//      Synchronize(UpdateCaption);
//
//   where UpdateCaption could look like:
//
//      void __fastcall mDNSServices::UpdateCaption()
//      {
//        Form1->Caption = "Updated in a thread";
//      }
//---------------------------------------------------------------------------
__fastcall mDNSServices::mDNSServices(bool CreateSuspended)
	: TThread(CreateSuspended)
{
assert(false);	// never called
}
//---------------------------------------------------------------------------

__fastcall mDNSServices::mDNSServices(bool CreateSuspended, uint32_t hostsaddr, bool Service1, bool Service2)
	: TThread(CreateSuspended)
{
// TODO : Right now the services are hard coded *****************************
// --- Service1 and Service2 are not used
//
// NOTE: I had a lot of trouble saving the correct hostsaddr in each thread.
// I eventually realized that that constructor is run in the context of
// the calling VCL thread. So saving the hostsaddr in MyHostSaddr saved it
// in a global memory location. I had to save it within the mDNSservices thread
// and then in the Execute() function (which runs in the context of
// each thread) had to save it into the MyHostSaddr which needed
// to be declared "__declspec( thread )". Someday I should rewrite
// this entire module so that every function is a member of mDNSServices.
//
LocalMyHostSaddr = hostsaddr;
// FreeOnTerminate is set so memory is automatically freed
FreeOnTerminate = true;
// ReturnValue is accessable using WaitFor()
ReturnValue = -1;
mDNSTerminate = false;
}

//---------------------------------------------------------------------------
void __fastcall mDNSServices::Execute()
{
	MyHostSaddr = LocalMyHostSaddr; // see note above in the constructor

	if (DEBUGGING && ptrTIUCommThread) {
		ptrTIUCommThread->PrintItem("mDNSServices Execute()", clGreen);
		}
	//char hostname[MAX_COMPUTERNAME_LENGTH + 1];
#ifdef _WIN32
	WORD versionWanted = MAKEWORD(2, 2);
	WSADATA wsaData;
	if (WSAStartup(versionWanted, &wsaData)) {
		if (DEBUGGING && ptrTIUCommThread) {
			ptrTIUCommThread->PrintItem("mDNSServices : Failed to initialize WinSock", clBlack);
			}
		return;
		} else {

		if (DEBUGGING && ptrTIUCommThread) {
			ptrTIUCommThread->PrintItem("mDNSServices : Initialized WinSock", clBlack);
			}
        }
#endif
/*  This was replaced by a call to LocalHostName()
	char hostname_buffer[MAX_COMPUTERNAME_LENGTH + 1];
	DWORD hostname_size = (DWORD)sizeof(hostname_buffer);
	if (GetComputerNameA(hostname_buffer, &hostname_size)) {
		strncpy(hostname, hostname_buffer, hostname_size);
		} else {
		strncpy(hostname, "dummy-host", hostname_size);
		}
*/
	// TODO : Right now the services are hard coded for three services *********************************************
    //
	const char * service[3] = {"_RTCMaster._udp.local", "_RTCHost._udp.local", "_RTCMaster._tcp.local"};
	int service_port[3] = {8899, 8890, 8897};

	if (DEBUGGING && ptrTIUCommThread) {
		//ptrTIUCommThread->PrintItem("mDNSServices Started in mDNSServices::Execute() on host " + String(hostname), clGreen);
		ptrTIUCommThread->PrintItem("mDNSServices Started in mDNSServices::Execute() on host " + LocalHostName(), clGreen);
		}
	(void)service_mdns(LocalHostName().c_str(), service, service_port, 3);

#ifdef _WIN32
	WSACleanup();
	if (DEBUGGING && ptrTIUCommThread) {
		ptrTIUCommThread->PrintItem("mDNSServices : Shutdown WinSock", clBlack);
    	}
#endif

return;
}
//---------------------------------------------------------------------------

void __fastcall mDNSServices::OnTerminate(TObject * Sender)     // called Automatically using Synchronize()
{
// not needed
//if (DEBUGGING && ptrTIUCommThread) ptrTIUCommThread->PrintItem("mDNSServices Terminated", clGreen);
//
mDNSTerminate = true;
}
//---------------------------------------------------------------------------

void __fastcall mDNSServices::KillMe(TObject * Sender)     // called Automatically using Synchronize()
{
mDNSTerminate = true;
}
//---------------------------------------------------------------------------

void __fastcall mDNSServices::mDNSQuery(AnsiString Service)
{
(void) send_mdns_query(Service.c_str(), MDNS_RECORDTYPE_PTR);
}
//---------------------------------------------------------------------------

