#include <glwebtools/internal/glwebtools_common.h>
#include <glwebtools/internal/glwebtools_memory.h>
#include <glwebtools/os/glwebtools_socket.h>
#include <glwebtools/internal/glwebtools_macro.h>
#if defined(_WIN32)
#if defined(WINAPI_FAMILY) && ((WINAPI_FAMILY==WINAPI_FAMILY_APP) || (WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP))
#else
#include <winsock2.h>
#include <Iphlpapi.h>
#endif
#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) //starting Windows 8 WideCharToMultiByte changes header
#include <Stringapiset.h>
#else
#include <Winnls.h>
#endif
#pragma comment(lib, "Iphlpapi.lib")
#elif defined(__linux__) || defined(ANDROID)
#include <string.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#ifdef OS_ANDROID
#include <sys/socket.h>
#endif
#elif defined(__APPLE__)
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <ifaddrs.h>
#if ! defined(IFT_ETHER)
#define IFT_ETHER 0x6/* Ethernet CSMACD */
#endif
#endif
namespace glwebtools
{
bool Socket::GetMacAddressFromIndex(size_t index, std::string& macAddress)
{
glwebtools::NetInterfaceInfoArray netIntArray;
bool result = GetNetInterfaceInfoArray(netIntArray);
if(!result)
{
//no error message since GetNetInterfaceInfoArray already printed one
return false;
}
if(index >= netIntArray.size())
{
GLWEBTOOLS_LOG_MINOR_ERROR("Index %d is out of bound (size = %u)", index, netIntArray.size());
return false;
}
macAddress = netIntArray[index].m_macAddress;
return true;
}
bool Socket::GetMacAddressFromName(const std::string& interfaceName, std::string& macAddress)
{
glwebtools::NetInterfaceInfoArray netIntArray;
bool result = GetNetInterfaceInfoArray(netIntArray);
if(!result)
{
//no error message since GetNetInterfaceInfoArray already printed one
return false;
}
for(size_t i = 0; i < netIntArray.size(); i++)
{
if(GLWEBTOOLS_STRCASECMP(interfaceName.c_str(), netIntArray[i].m_interfaceName.c_str()) == 0)
{
macAddress = netIntArray[i].m_macAddress;
return true;
}
}
return false;
}
#if defined(WIN32)
#if defined(WINAPI_FAMILY) && ((WINAPI_FAMILY==WINAPI_FAMILY_APP) || (WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP))
bool Socket::GetNetInterfaceInfoArray(glwebtools::NetInterfaceInfoArray& interfaceArray)
{
return false;
}
#else
bool Socket::GetNetInterfaceInfoArray(glwebtools::NetInterfaceInfoArray& interfaceArray)
{
PIP_ADAPTER_ADDRESSES pAdapterInfo = 0;
//get interface information
DWORD dwBufLen = sizeof(IP_ADAPTER_ADDRESSES);
while(pAdapterInfo == 0)
{
pAdapterInfo = static_cast<IP_ADAPTER_ADDRESSES*>(GLWEBTOOLS_ALLOC(dwBufLen));
if(!pAdapterInfo)
{
GLWEBTOOLS_LOG_MINOR_ERROR("Could not allocate %d bytes to get adapter info", dwBufLen);
return false;
}
ULONG status = GetAdaptersAddresses(
AF_INET,
0x003f,
NULL,
pAdapterInfo,
&dwBufLen
);
if(status == ERROR_BUFFER_OVERFLOW)
{
//need bigger buffer
GLWEBTOOLS_FREE(pAdapterInfo);
pAdapterInfo = 0;
}
else if(status == ERROR_NO_DATA)
{
GLWEBTOOLS_LOG_MINOR_ERROR("%s", "Could not get any adapter info");
return false;
}
else if(status != ERROR_SUCCESS)
{
GLWEBTOOLS_LOG_MINOR_ERROR("Could not get any adapter info with error : %d", static_cast<int>(status));
return false;
}
}
// Create the array
char mac_address[19];
PIP_ADAPTER_ADDRESSES pAA = pAdapterInfo;
while(pAA)
{
if(pAA->PhysicalAddressLength == 6 && pAA->IfType == IF_TYPE_ETHERNET_CSMACD)
{
glwebtools::NetInterfaceInfo netAdptInfo;
if(pAA->Description)
{
char description[512];
int result = WideCharToMultiByte(CP_UTF8, 0, pAA->Description, -1, description, 511, 0, 0);
if(result > 0)
netAdptInfo.m_interfaceName = description;
}
if(netAdptInfo.m_interfaceName.empty())
{
if(pAA->AdapterName)
{
netAdptInfo.m_interfaceName = pAA->AdapterName;
}
else
{
char name[32];
sprintf(name, "Adapter %d", interfaceArray.size());
netAdptInfo.m_interfaceName = name;
}
}
// Read from char array into a string object, into traditional Mac address format
sprintf(mac_address, "%02X:%02X:%02X:%02X:%02X:%02X", pAA->PhysicalAddress[0], pAA->PhysicalAddress[1], pAA->PhysicalAddress[2],
pAA->PhysicalAddress[3], pAA->PhysicalAddress[4], pAA->PhysicalAddress[5]);
netAdptInfo.m_macAddress = mac_address;
GLWEBTOOLS_LOG_VERBOSE("Adapter Name: %s", netAdptInfo.m_interfaceName.c_str());
GLWEBTOOLS_LOG_VERBOSE("Mac Address: %s", netAdptInfo.m_macAddress.c_str());
interfaceArray.push_back(netAdptInfo);
}
pAA = pAA->Next;
}
GLWEBTOOLS_FREE(pAdapterInfo);
return true;
}
#endif
#elif defined(__linux__) || defined(ANDROID)
bool Socket::GetNetInterfaceInfoArray(glwebtools::NetInterfaceInfoArray& interfaceArray)
{
ifreq ifr;
ifconf ifc;
char buf[1024];
int success = 0;
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock == -1)
{
GLWEBTOOLS_LOG_MINOR_ERROR("%s", "Could not open socket to get any adapter info");
return false;
};
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(sock, SIOCGIFCONF, &ifc) == -1)
{
GLWEBTOOLS_LOG_MINOR_ERROR("%s", "Could not get any adapter info");
return false;
}
ifreq* it = ifc.ifc_req;
const ifreq* const end = it + (ifc.ifc_len / sizeof(ifreq));
char mac_address[19];
for (; it != end; ++it)
{
strcpy(ifr.ifr_name, it->ifr_name);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0)
{
if (! (ifr.ifr_flags & IFF_LOOPBACK))
{ // don't count loopback
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0)
{
glwebtools::NetInterfaceInfo netAdptInfo;
netAdptInfo.m_interfaceName = ifr.ifr_name;
unsigned char macAddr[6];
memcpy(macAddr, ifr.ifr_hwaddr.sa_data, 6);
sprintf(mac_address, "%02X:%02X:%02X:%02X:%02X:%02X", macAddr[0], macAddr[1], macAddr[2],
macAddr[3], macAddr[4], macAddr[5]);
netAdptInfo.m_macAddress = mac_address;
GLWEBTOOLS_LOG_VERBOSE("Adapter Name: %s", netAdptInfo.m_interfaceName.c_str());
GLWEBTOOLS_LOG_VERBOSE("Mac Address: %s", netAdptInfo.m_macAddress.c_str());
interfaceArray.push_back(netAdptInfo);
}
}
}
else
{ /* handle error */
}
}
return true;
}
#elif defined(__APPLE__)
bool Socket::GetNetInterfaceInfoArray(glwebtools::NetInterfaceInfoArray& interfaceArray)
{
bool success;
struct ifaddrs * addrs;
const struct ifaddrs * cursor;
const struct sockaddr_dl * dlAddr;
const uint8_t * base;
success = getifaddrs(&addrs) == 0;
if (success)
{
cursor = addrs;
char mac_address[19];
while (cursor != NULL)
{
if ( (cursor->ifa_addr->sa_family == AF_LINK)
&& (((const struct sockaddr_dl *) cursor->ifa_addr)->sdl_type == IFT_ETHER) )
{
dlAddr = (const struct sockaddr_dl *) cursor->ifa_addr;
base = (const uint8_t *) &dlAddr->sdl_data[dlAddr->sdl_nlen];
if(dlAddr->sdl_alen == 6)
{
glwebtools::NetInterfaceInfo netAdptInfo;
if(cursor->ifa_name)
{
netAdptInfo.m_interfaceName = cursor->ifa_name;
}
else
{
char name[32];
sprintf(name, "Adapter %lu", interfaceArray.size());
netAdptInfo.m_interfaceName = name;
}
sprintf(mac_address, "%02X:%02X:%02X:%02X:%02X:%02X", base[0], base[1], base[2],
base[3], base[4], base[5]);
mac_address[18] = 0;
netAdptInfo.m_macAddress = mac_address;
GLWEBTOOLS_LOG_VERBOSE("Adapter Name: %s", netAdptInfo.m_interfaceName.c_str());
GLWEBTOOLS_LOG_VERBOSE("Mac Address: %s", netAdptInfo.m_macAddress.c_str());
interfaceArray.push_back(netAdptInfo);
}
}
cursor = cursor->ifa_next;
}
freeifaddrs(addrs);
}
else
{
return false;
}
return true;
}
#endif
}