#include <winsock2.h>
#include <iphlpapi.h>
#include <cstdio>
#include <cstdlib>
#include <locale>
// Link with Iphlpapi.lib
#pragma comment(lib, "IPHLPAPI.lib")

#define WORKING_BUFFER_SIZE 15000
#define MAX_TRIES 3

#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))

/* Note: could also use malloc() and free() */

void print_ip(CHAR addr[])
{
	printf("%d.", (unsigned char)addr[2]);
	printf("%d.", (unsigned char)addr[3]);
	printf("%d.", (unsigned char)addr[4]);
	printf("%d\n", (unsigned char)addr[5]);
}



int main(int argc, char **argv)
{
	setlocale(LC_ALL, "Russian");
	/* Declare and initialize variables */
	DWORD dwSize = 0;
	DWORD dwRetVal = 0;
	unsigned int i = 0;
	// Set the flags to pass to GetAdaptersAddresses
	ULONG flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS | GAA_FLAG_INCLUDE_ALL_COMPARTMENTS;
	// default to unspecified address family (both)
	ULONG family = AF_UNSPEC;
	LPVOID lpMsgBuf = nullptr;
	PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
	ULONG outBufLen = 0;
	ULONG Iterations = 0;
	PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
	PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
	PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = nullptr;
	PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = nullptr;
	PIP_ADAPTER_GATEWAY_ADDRESS pGateway = nullptr;
	IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = nullptr;
	IP_ADAPTER_PREFIX *pPrefix = nullptr;

	if (argc != 2)
	{
		printf(" Usage: getadapteraddresses family\n");
		printf("        getadapteraddresses 4 (for IPv4)\n");
		printf("        getadapteraddresses 6 (for IPv6)\n");
		printf("        getadapteraddresses A (for both IPv4 and IPv6)\n");
		exit(1);
	}

	if (atoi(argv[1]) == 4)
	{
		family = AF_INET;
	}
	else if (atoi(argv[1]) == 6)
	{
		family = AF_INET6;
	}

	printf("Calling GetAdaptersAddresses function with family = ");

	if (family == AF_INET)
	{
		printf("AF_INET\n");
	}

	if (family == AF_INET6)
	{
		printf("AF_INET6\n");
	}

	if (family == AF_UNSPEC)
	{
		printf("AF_UNSPEC\n\n");
	}

	// Allocate a 15 KB buffer to start with.
	outBufLen = WORKING_BUFFER_SIZE;

	do
	{
		pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC(outBufLen);

		if (pAddresses == nullptr)
		{
			printf
			("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
			exit(1);
		}

		dwRetVal =
		    GetAdaptersAddresses(family, flags, nullptr, pAddresses, &outBufLen);

		if (dwRetVal == ERROR_BUFFER_OVERFLOW)
		{
			FREE(pAddresses);
			pAddresses = nullptr;
		}
		else
		{
			break;
		}

		Iterations++;
	}
	while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));

	if (dwRetVal == NO_ERROR)
	{
		// If successful, output some information from the data we received
		pCurrAddresses = pAddresses;

		while (pCurrAddresses)
		{
			printf("\tLength of the IP_ADAPTER_ADDRESS struct: %ld\n",
			       pCurrAddresses->Length);
			printf("\tIfIndex (IPv4 interface): %u\n", pCurrAddresses->IfIndex);
			printf("\tAdapter name: %s\n", pCurrAddresses->AdapterName);
			pUnicast = pCurrAddresses->FirstUnicastAddress;

			if (pUnicast != nullptr)
			{
				for (i = 0; pUnicast != nullptr; i++)
				{
					print_ip(pUnicast->Address.lpSockaddr->sa_data);
					pUnicast = pUnicast->Next;
				}

				printf("\tNumber of Unicast Addresses: %d\n", i);
			}
			else
			{
				printf("\tNo Unicast Addresses\n");
			}

			pAnycast = pCurrAddresses->FirstAnycastAddress;

			if (pAnycast)
			{
				for (i = 0; pAnycast != nullptr; i++)
				{
					print_ip(pAnycast->Address.lpSockaddr->sa_data);
					pAnycast = pAnycast->Next;
				}

				printf("\tNumber of Anycast Addresses: %d\n", i);
			}
			else
			{
				printf("\tNo Anycast Addresses\n");
			}

			pMulticast = pCurrAddresses->FirstMulticastAddress;

			if (pMulticast)
			{
				for (i = 0; pMulticast != nullptr; i++)
				{
					print_ip(pMulticast->Address.lpSockaddr->sa_data);
					pMulticast = pMulticast->Next;
				}

				printf("\tNumber of Multicast Addresses: %d\n", i);
			}
			else
			{
				printf("\tNo Multicast Addresses\n");
			}

			pGateway = pCurrAddresses->FirstGatewayAddress;

			if (pGateway)
			{
				for (i = 0; pGateway != nullptr; i++)
				{
					print_ip(pGateway->Address.lpSockaddr->sa_data);
					pGateway = pGateway->Next;
				}

				printf("\tNumber of Gateway Addresses: %d\n", i);
			}
			else
			{
				printf("\tNo Gateway Addresses\n");
			}

			pDnServer = pCurrAddresses->FirstDnsServerAddress;

			if (pDnServer)
			{
				for (i = 0; pDnServer != nullptr; i++)
				{
					print_ip(pDnServer->Address.lpSockaddr->sa_data);
					pDnServer = pDnServer->Next;
				}

				printf("\tNumber of DNS Server Addresses: %d\n", i);
			}
			else
			{
				printf("\tNo DNS Server Addresses\n");
			}

			printf("\tDNS Suffix: %wS\n", pCurrAddresses->DnsSuffix);
			printf("\tDescription: %wS\n", pCurrAddresses->Description);
			printf("\tFriendly name: %wS\n", pCurrAddresses->FriendlyName);

			if (pCurrAddresses->PhysicalAddressLength != 0)
			{
				printf("\tPhysical address: ");

				for (i = 0; i < (int)pCurrAddresses->PhysicalAddressLength;
				        i++)
				{
					if (i == (pCurrAddresses->PhysicalAddressLength - 1))
						printf("%.2X\n",
						       (int)pCurrAddresses->PhysicalAddress[i]);
					else
						printf("%.2X-",
						       (int)pCurrAddresses->PhysicalAddress[i]);
				}
			}

			printf("\tFlags: %ld\n", pCurrAddresses->Flags);
			printf("\tMtu: %lu\n", pCurrAddresses->Mtu);
			printf("\tIfType: %ld\n", pCurrAddresses->IfType);
			printf("\tOperStatus: %ld\n", pCurrAddresses->OperStatus);
			printf("\tIpv6IfIndex (IPv6 interface): %u\n",
			       pCurrAddresses->Ipv6IfIndex);
			printf("\tZoneIndices (hex): ");

			for (i = 0; i < 16; i++)
			{
				printf("%lx ", pCurrAddresses->ZoneIndices[i]);
			}

			printf("\n");
			printf("\tTransmit link speed: %I64u\n", pCurrAddresses->TransmitLinkSpeed);
			printf("\tReceive link speed: %I64u\n", pCurrAddresses->ReceiveLinkSpeed);
			pPrefix = pCurrAddresses->FirstPrefix;

			if (pPrefix)
			{
				for (i = 0; pPrefix != nullptr; i++)
				{
					print_ip(pPrefix->Address.lpSockaddr->sa_data);
					pPrefix = pPrefix->Next;
				}

				printf("\tNumber of IP Adapter Prefix entries: %d\n", i);
			}
			else
			{
				printf("\tNumber of IP Adapter Prefix entries: 0\n");
			}

			printf("\n");
			pCurrAddresses = pCurrAddresses->Next;
		}
	}
	else
	{
		printf("Call to GetAdaptersAddresses failed with error: %d\n",
		       dwRetVal);

		if (dwRetVal == ERROR_NO_DATA)
		{
			printf("\tNo addresses were found for the requested parameters\n");
		}
		else
		{
			if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
			                  FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
			                  nullptr, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
			                  // Default language
			                  (LPTSTR)&lpMsgBuf, 0, nullptr))
			{
				printf("\tError: %s", lpMsgBuf);
				LocalFree(lpMsgBuf);

				if (pAddresses)
				{
					FREE(pAddresses);
				}

				exit(1);
			}
		}
	}

	if (pAddresses)
	{
		FREE(pAddresses);
	}

	return 0;
}


/*
#include "stdafx.h"
#include "pcap.h"
#include <iostream>
using namespace std;
#pragma comment (lib, "wpcap.lib")
#pragma comment (lib, "Packet.lib")
char *dev;
char errbuf[PCAP_ERRBUF_SIZE];
int start;
pcap_t *handle;
const u_char btPacket[]={0x00 ,0x21 ,0x56 ,0xD8 ,0xDC ,0x1B ,0x00 ,0x16 ,0x36 ,0x95 ,0xAE ,0xAB ,0x88 ,0x64 ,0x11 ,0x00
                        ,0x49 ,0x7F ,0x00 ,0x2D ,0x00 ,0x21 ,0x45 ,0x00 ,0x00 ,0x2B ,0x16 ,0xC9 ,0x00 ,0x00 ,0xC8 ,0x11
                        ,0x26 ,0x0C ,0xB2 ,0x16 ,0xC0 ,0x83 ,0x5B ,0xDA ,0xE7 ,0x78 ,0x07 ,0x2B ,0x27 ,0x09 ,0x00 ,0x17
                        ,0xA0 ,0x8E ,0x53 ,0x41 ,0x4D ,0x50 ,0x5B ,0xDA ,0xE7 ,0x78 ,0x09 ,0x27 ,0x70 ,0xE0 ,0x1D ,0x24
                        ,0x00};

int main()
{
dev = pcap_lookupdev(errbuf);
handle = pcap_open_live(dev, BUFSIZ, 1, 0, errbuf);
while(true)
{
    cout << "Please enter: 123" << endl;
    cin >> start;
    if (start == 123)
    {
pcap_sendpacket(handle, btPacket, sizeof(btPacket));
    }
}
}

*/