Newer
Older
Import / projects / Gameloft / glwebtools / source / glwebtools / glwebtools_socket_base.cpp
#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
}