From 539eb3e1ee41778bbd9a27181fa30a91ab903f40 Mon Sep 17 00:00:00 2001 From: fuzzard Date: Sun, 12 May 2019 12:36:15 +1000 Subject: [posix] relocate common platform/network/linux to platform/posix Move common elements to posix folder --- cmake/treedata/freebsd/subdirs.txt | 1 + cmake/treedata/ios/subdirs.txt | 2 +- cmake/treedata/linux/subdirs.txt | 1 + cmake/treedata/osx/subdirs.txt | 2 +- xbmc/network/Network.h | 2 +- xbmc/platform/linux/network/CMakeLists.txt | 16 +- xbmc/platform/linux/network/NetworkLinux.cpp | 589 --------------------------- xbmc/platform/linux/network/NetworkLinux.h | 70 ---- xbmc/platform/posix/network/CMakeLists.txt | 5 + xbmc/platform/posix/network/NetworkLinux.cpp | 589 +++++++++++++++++++++++++++ xbmc/platform/posix/network/NetworkLinux.h | 70 ++++ 11 files changed, 675 insertions(+), 672 deletions(-) delete mode 100644 xbmc/platform/linux/network/NetworkLinux.cpp delete mode 100644 xbmc/platform/linux/network/NetworkLinux.h create mode 100644 xbmc/platform/posix/network/CMakeLists.txt create mode 100644 xbmc/platform/posix/network/NetworkLinux.cpp create mode 100644 xbmc/platform/posix/network/NetworkLinux.h diff --git a/cmake/treedata/freebsd/subdirs.txt b/cmake/treedata/freebsd/subdirs.txt index fd8ed5f21e..38cc9559a8 100644 --- a/cmake/treedata/freebsd/subdirs.txt +++ b/cmake/treedata/freebsd/subdirs.txt @@ -11,5 +11,6 @@ xbmc/platform/linux/powermanagement platform/linux/powermanagement xbmc/platform/linux/storage platform/linux/storage xbmc/platform/posix platform/posix xbmc/platform/posix/filesystem platform/posix/filesystem +xbmc/platform/posix/network platform/posix/network xbmc/platform/posix/utils platform/posix/utils xbmc/windowing/linux windowing/linux diff --git a/cmake/treedata/ios/subdirs.txt b/cmake/treedata/ios/subdirs.txt index a3a03be965..9442f337ce 100644 --- a/cmake/treedata/ios/subdirs.txt +++ b/cmake/treedata/ios/subdirs.txt @@ -8,8 +8,8 @@ xbmc/platform/darwin/ios-common platform/ios-common xbmc/platform/darwin/network platform/darwin/network xbmc/platform/darwin/storage platform/storage xbmc/platform/linux platform/linux -xbmc/platform/linux/network platform/linux/network xbmc/platform/posix posix xbmc/platform/posix/filesystem platform/posix/filesystem +xbmc/platform/posix/network platform/posix/network xbmc/platform/posix/utils platform/posix/utils xbmc/windowing/ios windowing/ios diff --git a/cmake/treedata/linux/subdirs.txt b/cmake/treedata/linux/subdirs.txt index 7619e2e307..3809dd1d7a 100644 --- a/cmake/treedata/linux/subdirs.txt +++ b/cmake/treedata/linux/subdirs.txt @@ -10,5 +10,6 @@ xbmc/platform/linux/powermanagement platform/linux/powermanagement xbmc/platform/linux/storage platform/linux/storage xbmc/platform/posix platform/posix xbmc/platform/posix/filesystem platform/posix/filesystem +xbmc/platform/posix/network platform/posix/network xbmc/platform/posix/utils platform/posix/utils xbmc/windowing/linux windowing/linux diff --git a/cmake/treedata/osx/subdirs.txt b/cmake/treedata/osx/subdirs.txt index 943c366242..9f5f025c65 100644 --- a/cmake/treedata/osx/subdirs.txt +++ b/cmake/treedata/osx/subdirs.txt @@ -7,8 +7,8 @@ xbmc/platform/darwin/osx/peripherals platform/osx/peripherals xbmc/platform/darwin/osx/powermanagement platform/darwin/osx/powermanagement xbmc/platform/darwin/storage platform/storage xbmc/platform/linux platform/linux -xbmc/platform/linux/network platform/linux/network xbmc/platform/posix posix xbmc/platform/posix/filesystem platform/posix/filesystem +xbmc/platform/posix/network platform/posix/network xbmc/platform/posix/utils platform/posix/utils xbmc/windowing/osx windowing/osx diff --git a/xbmc/network/Network.h b/xbmc/network/Network.h index eba8941a32..70bbab6286 100644 --- a/xbmc/network/Network.h +++ b/xbmc/network/Network.h @@ -115,7 +115,7 @@ public: #if defined(TARGET_ANDROID) #include "platform/android/network/NetworkAndroid.h" #elif defined(HAS_LINUX_NETWORK) -#include "platform/linux/network/NetworkLinux.h" +#include "platform/posix/network/NetworkLinux.h" #elif defined(HAS_WIN32_NETWORK) #include "platform/win32/network/NetworkWin32.h" #elif defined(HAS_WIN10_NETWORK) diff --git a/xbmc/platform/linux/network/CMakeLists.txt b/xbmc/platform/linux/network/CMakeLists.txt index 9a99ed1c20..2920c3c0f4 100644 --- a/xbmc/platform/linux/network/CMakeLists.txt +++ b/xbmc/platform/linux/network/CMakeLists.txt @@ -1,12 +1,8 @@ -set(SOURCES NetworkLinux.cpp) - -set(HEADERS NetworkLinux.h) - if(AVAHI_FOUND) - list(APPEND SOURCES ZeroconfAvahi.cpp - ZeroconfBrowserAvahi.cpp) - list(APPEND HEADERS ZeroconfAvahi.h - ZeroconfBrowserAvahi.h) -endif() + set(SOURCES ZeroconfAvahi.cpp + ZeroconfBrowserAvahi.cpp) + set(HEADERS ZeroconfAvahi.h + ZeroconfBrowserAvahi.h) -core_add_library(platform_linux_network) + core_add_library(platform_linux_network) +endif() diff --git a/xbmc/platform/linux/network/NetworkLinux.cpp b/xbmc/platform/linux/network/NetworkLinux.cpp deleted file mode 100644 index 35abf12616..0000000000 --- a/xbmc/platform/linux/network/NetworkLinux.cpp +++ /dev/null @@ -1,589 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#include - -#include -#include -#include -#include -#if defined(TARGET_LINUX) - #include - #include - #include -#endif -#ifdef TARGET_ANDROID -#include "platform/android/bionic_supplement/bionic_supplement.h" -#include "sys/system_properties.h" -#include -#endif -#include -#include -#if defined(TARGET_DARWIN) - #include - #include - #include -#if defined(TARGET_DARWIN_OSX) - #include - #include - #include -#else //IOS - #include "platform/darwin/network/ioshacks.h" -#endif - #include -#elif defined(TARGET_FREEBSD) - #include - #include - #include - #include - #include - #include - #include - #include -#else - #include -#endif -#include "PlatformDefs.h" -#include "NetworkLinux.h" -#include "Util.h" -#include "utils/log.h" -#include "utils/StringUtils.h" - -CNetworkInterfaceLinux::CNetworkInterfaceLinux(CNetworkLinux* network, std::string interfaceName, char interfaceMacAddrRaw[6]): - m_interfaceName(interfaceName), - m_interfaceMacAdr(StringUtils::Format("%02X:%02X:%02X:%02X:%02X:%02X", - (uint8_t)interfaceMacAddrRaw[0], - (uint8_t)interfaceMacAddrRaw[1], - (uint8_t)interfaceMacAddrRaw[2], - (uint8_t)interfaceMacAddrRaw[3], - (uint8_t)interfaceMacAddrRaw[4], - (uint8_t)interfaceMacAddrRaw[5])) -{ - m_network = network; - memcpy(m_interfaceMacAddrRaw, interfaceMacAddrRaw, sizeof(m_interfaceMacAddrRaw)); -} - -CNetworkInterfaceLinux::~CNetworkInterfaceLinux(void) = default; - -bool CNetworkInterfaceLinux::IsEnabled() const -{ - struct ifreq ifr; - strcpy(ifr.ifr_name, m_interfaceName.c_str()); - if (ioctl(m_network->GetSocket(), SIOCGIFFLAGS, &ifr) < 0) - return false; - - return ((ifr.ifr_flags & IFF_UP) == IFF_UP); -} - -bool CNetworkInterfaceLinux::IsConnected() const -{ - struct ifreq ifr; - int zero = 0; - memset(&ifr,0,sizeof(struct ifreq)); - strcpy(ifr.ifr_name, m_interfaceName.c_str()); - if (ioctl(m_network->GetSocket(), SIOCGIFFLAGS, &ifr) < 0) - return false; - - // ignore loopback - int iRunning = ( (ifr.ifr_flags & IFF_RUNNING) && (!(ifr.ifr_flags & IFF_LOOPBACK))); - - if (ioctl(m_network->GetSocket(), SIOCGIFADDR, &ifr) < 0) - return false; - - // return only interfaces which has ip address - return iRunning && (0 != memcmp(ifr.ifr_addr.sa_data+sizeof(short), &zero, sizeof(int))); -} - -std::string CNetworkInterfaceLinux::GetMacAddress() const -{ - return m_interfaceMacAdr; -} - -void CNetworkInterfaceLinux::GetMacAddressRaw(char rawMac[6]) const -{ - memcpy(rawMac, m_interfaceMacAddrRaw, 6); -} - -std::string CNetworkInterfaceLinux::GetCurrentIPAddress(void) const -{ - std::string result; - - struct ifreq ifr; - strcpy(ifr.ifr_name, m_interfaceName.c_str()); - ifr.ifr_addr.sa_family = AF_INET; - if (ioctl(m_network->GetSocket(), SIOCGIFADDR, &ifr) >= 0) - { - result = inet_ntoa((*((struct sockaddr_in *)&ifr.ifr_addr)).sin_addr); - } - - return result; -} - -std::string CNetworkInterfaceLinux::GetCurrentNetmask(void) const -{ - std::string result; - - struct ifreq ifr; - strcpy(ifr.ifr_name, m_interfaceName.c_str()); - ifr.ifr_addr.sa_family = AF_INET; - if (ioctl(m_network->GetSocket(), SIOCGIFNETMASK, &ifr) >= 0) - { - result = inet_ntoa((*((struct sockaddr_in*)&ifr.ifr_addr)).sin_addr); - } - - return result; -} - -std::string CNetworkInterfaceLinux::GetCurrentDefaultGateway(void) const -{ - std::string result; - -#if defined(TARGET_DARWIN) - FILE* pipe = popen("echo \"show State:/Network/Global/IPv4\" | scutil | grep Router", "r"); - usleep(100000); - if (pipe) - { - std::string tmpStr; - char buffer[256] = {'\0'}; - if (fread(buffer, sizeof(char), sizeof(buffer), pipe) > 0 && !ferror(pipe)) - { - tmpStr = buffer; - if (tmpStr.length() >= 11) - result = tmpStr.substr(11); - } - pclose(pipe); - } - if (result.empty()) - CLog::Log(LOGWARNING, "Unable to determine gateway"); -#elif defined(TARGET_FREEBSD) - size_t needed; - int mib[6]; - char *buf, *next, *lim; - char line[16]; - struct rt_msghdr *rtm; - struct sockaddr *sa; - struct sockaddr_in *sockin; - - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; - mib[3] = 0; - mib[4] = NET_RT_DUMP; - mib[5] = 0; - if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) - return result; - - if ((buf = (char *)malloc(needed)) == NULL) - return result; - - if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { - free(buf); - return result; - } - - lim = buf + needed; - for (next = buf; next < lim; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)next; - sa = (struct sockaddr *)(rtm + 1); - sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa); - sockin = (struct sockaddr_in *)sa; - if (inet_ntop(AF_INET, &sockin->sin_addr.s_addr, - line, sizeof(line)) == NULL) { - free(buf); - return result; - } - result = line; - break; - } - free(buf); -#else - FILE* fp = fopen("/proc/net/route", "r"); - if (!fp) - { - // TBD: Error - return result; - } - - char* line = NULL; - char iface[16]; - char dst[128]; - char gateway[128]; - size_t linel = 0; - int n; - int linenum = 0; - while (getdelim(&line, &linel, '\n', fp) > 0) - { - // skip first two lines - if (linenum++ < 1) - continue; - - // search where the word begins - n = sscanf(line, "%15s %127s %127s", - iface, dst, gateway); - - if (n < 3) - continue; - - if (strcmp(iface, m_interfaceName.c_str()) == 0 && - strcmp(dst, "00000000") == 0 && - strcmp(gateway, "00000000") != 0) - { - unsigned char gatewayAddr[4]; - int len = CNetworkBase::ParseHex(gateway, gatewayAddr); - if (len == 4) - { - struct in_addr in; - in.s_addr = (gatewayAddr[0] << 24) | (gatewayAddr[1] << 16) | - (gatewayAddr[2] << 8) | (gatewayAddr[3]); - result = inet_ntoa(in); - break; - } - } - } - free(line); - fclose(fp); -#endif - - return result; -} - -CNetworkLinux::CNetworkLinux() - : CNetworkBase() -{ - m_sock = socket(AF_INET, SOCK_DGRAM, 0); - queryInterfaceList(); -} - -CNetworkLinux::~CNetworkLinux(void) -{ - if (m_sock != -1) - close(CNetworkLinux::m_sock); - - std::vector::iterator it = m_interfaces.begin(); - while(it != m_interfaces.end()) - { - CNetworkInterface* nInt = *it; - delete nInt; - it = m_interfaces.erase(it); - } -} - -std::vector& CNetworkLinux::GetInterfaceList(void) -{ - return m_interfaces; -} - -//! @bug -//! Overwrite the GetFirstConnectedInterface and requery -//! the interface list if no connected device is found -//! this fixes a bug when no network is available after first start of xbmc -//! and the interface comes up during runtime -CNetworkInterface* CNetworkLinux::GetFirstConnectedInterface(void) -{ - CNetworkInterface *pNetIf=CNetworkBase::GetFirstConnectedInterface(); - - // no connected Interfaces found? - requeryInterfaceList - if (!pNetIf) - { - CLog::Log(LOGDEBUG,"%s no connected interface found - requery list",__FUNCTION__); - queryInterfaceList(); - //retry finding a connected if - pNetIf = CNetworkBase::GetFirstConnectedInterface(); - } - - return pNetIf; -} - - -void CNetworkLinux::GetMacAddress(const std::string& interfaceName, char rawMac[6]) -{ - memset(rawMac, 0, 6); -#if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) - -#if !defined(IFT_ETHER) -#define IFT_ETHER 0x6/* Ethernet CSMACD */ -#endif - const struct sockaddr_dl* dlAddr = NULL; - const uint8_t * base = NULL; - // Query the list of interfaces. - struct ifaddrs *list; - struct ifaddrs *interface; - - if( getifaddrs(&list) < 0 ) - { - return; - } - - for(interface = list; interface != NULL; interface = interface->ifa_next) - { - if(interfaceName == interface->ifa_name) - { - if ( (interface->ifa_addr->sa_family == AF_LINK) && (((const struct sockaddr_dl *) interface->ifa_addr)->sdl_type == IFT_ETHER) ) - { - dlAddr = (const struct sockaddr_dl *) interface->ifa_addr; - base = (const uint8_t *) &dlAddr->sdl_data[dlAddr->sdl_nlen]; - - if( dlAddr->sdl_alen > 5 ) - { - memcpy(rawMac, base, 6); - } - } - break; - } - } - - freeifaddrs(list); - -#else - - struct ifreq ifr; - strcpy(ifr.ifr_name, interfaceName.c_str()); - if (ioctl(GetSocket(), SIOCGIFHWADDR, &ifr) >= 0) - { - memcpy(rawMac, ifr.ifr_hwaddr.sa_data, 6); - } -#endif -} - -void CNetworkLinux::queryInterfaceList() -{ - char macAddrRaw[6]; - m_interfaces.clear(); - -#if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) - - // Query the list of interfaces. - struct ifaddrs *list; - if (getifaddrs(&list) < 0) - return; - - struct ifaddrs *cur; - for(cur = list; cur != NULL; cur = cur->ifa_next) - { - if(cur->ifa_addr->sa_family != AF_INET) - continue; - - GetMacAddress(cur->ifa_name, macAddrRaw); - - // only add interfaces with non-zero mac addresses - if (macAddrRaw[0] || macAddrRaw[1] || macAddrRaw[2] || macAddrRaw[3] || macAddrRaw[4] || macAddrRaw[5]) - // Add the interface. - m_interfaces.push_back(new CNetworkInterfaceLinux(this, cur->ifa_name, macAddrRaw)); - } - - freeifaddrs(list); - -#else - FILE* fp = fopen("/proc/net/dev", "r"); - if (!fp) - { - // TBD: Error - return; - } - - char* line = NULL; - size_t linel = 0; - int n; - char* p; - int linenum = 0; - while (getdelim(&line, &linel, '\n', fp) > 0) - { - // skip first two lines - if (linenum++ < 2) - continue; - - // search where the word begins - p = line; - while (isspace(*p)) - ++p; - - // read word until : - n = strcspn(p, ": \t"); - p[n] = 0; - - // save the result - std::string interfaceName = p; - GetMacAddress(interfaceName, macAddrRaw); - - // only add interfaces with non-zero mac addresses - if (macAddrRaw[0] || macAddrRaw[1] || macAddrRaw[2] || macAddrRaw[3] || macAddrRaw[4] || macAddrRaw[5]) - m_interfaces.push_back(new CNetworkInterfaceLinux(this, interfaceName, macAddrRaw)); - } - free(line); - fclose(fp); -#endif -} - -std::vector CNetworkLinux::GetNameServers(void) -{ - std::vector result; - -#if defined(TARGET_DARWIN) - FILE* pipe = popen("scutil --dns | grep \"nameserver\" | tail -n2", "r"); - usleep(100000); - if (pipe) - { - std::vector tmpStr; - char buffer[256] = {'\0'}; - if (fread(buffer, sizeof(char), sizeof(buffer), pipe) > 0 && !ferror(pipe)) - { - tmpStr = StringUtils::Split(buffer, "\n"); - for (unsigned int i = 0; i < tmpStr.size(); i ++) - { - // result looks like this - > ' nameserver[0] : 192.168.1.1' - // 2 blank spaces + 13 in 'nameserver[0]' + blank + ':' + blank == 18 :) - if (tmpStr[i].length() >= 18) - result.push_back(tmpStr[i].substr(18)); - } - } - pclose(pipe); - } - if (result.empty()) - CLog::Log(LOGWARNING, "Unable to determine nameserver"); -#elif defined(TARGET_ANDROID) - char nameserver[PROP_VALUE_MAX]; - - if (__system_property_get("net.dns1",nameserver)) - result.push_back(nameserver); - if (__system_property_get("net.dns2",nameserver)) - result.push_back(nameserver); - if (__system_property_get("net.dns3",nameserver)) - result.push_back(nameserver); - - if (!result.size()) - CLog::Log(LOGWARNING, "Unable to determine nameserver"); -#else - res_init(); - - for (int i = 0; i < _res.nscount; i ++) - { - std::string ns = inet_ntoa(_res.nsaddr_list[i].sin_addr); - result.push_back(ns); - } -#endif - return result; -} - -bool CNetworkLinux::PingHost(unsigned long remote_ip, unsigned int timeout_ms) -{ - char cmd_line [64]; - - struct in_addr host_ip; - host_ip.s_addr = remote_ip; - -#if defined (TARGET_DARWIN) || defined (TARGET_FREEBSD) - sprintf(cmd_line, "ping -c 1 -t %d %s", timeout_ms / 1000 + (timeout_ms % 1000) != 0, inet_ntoa(host_ip)); -#else - sprintf(cmd_line, "ping -c 1 -w %d %s", timeout_ms / 1000 + (timeout_ms % 1000) != 0, inet_ntoa(host_ip)); -#endif - - int status = -1; -#if !defined (TARGET_DARWIN_IOS) // no system calls allowed since ios11 - status = system (cmd_line); -#endif - int result = WIFEXITED(status) ? WEXITSTATUS(status) : -1; - - // http://linux.about.com/od/commands/l/blcmdl8_ping.htm ; - // 0 reply - // 1 no reply - // else some error - - if (result < 0 || result > 1) - CLog::Log(LOGERROR, "Ping fail : status = %d, errno = %d : '%s'", status, errno, cmd_line); - - return result == 0; -} - -#if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) -bool CNetworkInterfaceLinux::GetHostMacAddress(unsigned long host_ip, std::string& mac) const -{ - bool ret = false; - size_t needed; - char *buf, *next; - struct rt_msghdr *rtm; - struct sockaddr_inarp *sin; - struct sockaddr_dl *sdl; - int mib[6]; - - mac = ""; - - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; - mib[3] = AF_INET; - mib[4] = NET_RT_FLAGS; - mib[5] = RTF_LLINFO; - - if (sysctl(mib, ARRAY_SIZE(mib), NULL, &needed, NULL, 0) == 0) - { - buf = (char*)malloc(needed); - if (buf) - { - if (sysctl(mib, ARRAY_SIZE(mib), buf, &needed, NULL, 0) == 0) - { - for (next = buf; next < buf + needed; next += rtm->rtm_msglen) - { - - rtm = (struct rt_msghdr *)next; - sin = (struct sockaddr_inarp *)(rtm + 1); - sdl = (struct sockaddr_dl *)(sin + 1); - - if (host_ip != sin->sin_addr.s_addr || sdl->sdl_alen < 6) - continue; - - u_char *cp = (u_char*)LLADDR(sdl); - - mac = StringUtils::Format("%02X:%02X:%02X:%02X:%02X:%02X", - cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); - ret = true; - break; - } - } - free(buf); - } - } - return ret; -} -#else -bool CNetworkInterfaceLinux::GetHostMacAddress(unsigned long host_ip, std::string& mac) const -{ - struct arpreq areq; - struct sockaddr_in* sin; - - memset(&areq, 0x0, sizeof(areq)); - - sin = (struct sockaddr_in *) &areq.arp_pa; - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = host_ip; - - sin = (struct sockaddr_in *) &areq.arp_ha; - sin->sin_family = ARPHRD_ETHER; - - strncpy(areq.arp_dev, m_interfaceName.c_str(), sizeof(areq.arp_dev)); - areq.arp_dev[sizeof(areq.arp_dev)-1] = '\0'; - - int result = ioctl (m_network->GetSocket(), SIOCGARP, (caddr_t) &areq); - - if (result != 0) - { -// CLog::Log(LOGERROR, "%s - GetHostMacAddress/ioctl failed with errno (%d)", __FUNCTION__, errno); - return false; - } - - struct sockaddr* res = &areq.arp_ha; - mac = StringUtils::Format("%02X:%02X:%02X:%02X:%02X:%02X", - (uint8_t) res->sa_data[0], (uint8_t) res->sa_data[1], (uint8_t) res->sa_data[2], - (uint8_t) res->sa_data[3], (uint8_t) res->sa_data[4], (uint8_t) res->sa_data[5]); - - for (int i=0; i<6; ++i) - if (res->sa_data[i]) - return true; - - return false; -} -#endif diff --git a/xbmc/platform/linux/network/NetworkLinux.h b/xbmc/platform/linux/network/NetworkLinux.h deleted file mode 100644 index 13d87076ae..0000000000 --- a/xbmc/platform/linux/network/NetworkLinux.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include -#include -#include -#include "network/Network.h" - -class CNetworkLinux; - -class CNetworkInterfaceLinux : public CNetworkInterface -{ -public: - CNetworkInterfaceLinux(CNetworkLinux* network, std::string interfaceName, char interfaceMacAddrRaw[6]); - ~CNetworkInterfaceLinux(void) override; - - bool IsEnabled(void) const override; - bool IsConnected(void) const override; - - std::string GetMacAddress(void) const override; - void GetMacAddressRaw(char rawMac[6]) const override; - - bool GetHostMacAddress(unsigned long host, std::string& mac) const override; - - std::string GetCurrentIPAddress() const override; - std::string GetCurrentNetmask() const override; - std::string GetCurrentDefaultGateway(void) const override; - -private: - std::string m_interfaceName; - std::string m_interfaceMacAdr; - char m_interfaceMacAddrRaw[6]; - CNetworkLinux* m_network; -}; - -class CNetworkLinux : public CNetworkBase -{ -public: - CNetworkLinux(); - ~CNetworkLinux(void) override; - - // Return the list of interfaces - std::vector& GetInterfaceList(void) override; - CNetworkInterface* GetFirstConnectedInterface(void) override; - - // Ping remote host - bool PingHost(unsigned long host, unsigned int timeout_ms = 2000) override; - - // Get/set the nameserver(s) - std::vector GetNameServers(void) override; - - friend class CNetworkInterfaceLinux; - -private: - int GetSocket() { return m_sock; } - void GetMacAddress(const std::string& interfaceName, char macAddrRaw[6]); - void queryInterfaceList(); - std::vector m_interfaces; - int m_sock; -}; - -using CNetwork = CNetworkLinux; - diff --git a/xbmc/platform/posix/network/CMakeLists.txt b/xbmc/platform/posix/network/CMakeLists.txt new file mode 100644 index 0000000000..f68b86802d --- /dev/null +++ b/xbmc/platform/posix/network/CMakeLists.txt @@ -0,0 +1,5 @@ +set(SOURCES NetworkLinux.cpp) + +set(HEADERS NetworkLinux.h) + +core_add_library(platform_posix_network) diff --git a/xbmc/platform/posix/network/NetworkLinux.cpp b/xbmc/platform/posix/network/NetworkLinux.cpp new file mode 100644 index 0000000000..35abf12616 --- /dev/null +++ b/xbmc/platform/posix/network/NetworkLinux.cpp @@ -0,0 +1,589 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include + +#include +#include +#include +#include +#if defined(TARGET_LINUX) + #include + #include + #include +#endif +#ifdef TARGET_ANDROID +#include "platform/android/bionic_supplement/bionic_supplement.h" +#include "sys/system_properties.h" +#include +#endif +#include +#include +#if defined(TARGET_DARWIN) + #include + #include + #include +#if defined(TARGET_DARWIN_OSX) + #include + #include + #include +#else //IOS + #include "platform/darwin/network/ioshacks.h" +#endif + #include +#elif defined(TARGET_FREEBSD) + #include + #include + #include + #include + #include + #include + #include + #include +#else + #include +#endif +#include "PlatformDefs.h" +#include "NetworkLinux.h" +#include "Util.h" +#include "utils/log.h" +#include "utils/StringUtils.h" + +CNetworkInterfaceLinux::CNetworkInterfaceLinux(CNetworkLinux* network, std::string interfaceName, char interfaceMacAddrRaw[6]): + m_interfaceName(interfaceName), + m_interfaceMacAdr(StringUtils::Format("%02X:%02X:%02X:%02X:%02X:%02X", + (uint8_t)interfaceMacAddrRaw[0], + (uint8_t)interfaceMacAddrRaw[1], + (uint8_t)interfaceMacAddrRaw[2], + (uint8_t)interfaceMacAddrRaw[3], + (uint8_t)interfaceMacAddrRaw[4], + (uint8_t)interfaceMacAddrRaw[5])) +{ + m_network = network; + memcpy(m_interfaceMacAddrRaw, interfaceMacAddrRaw, sizeof(m_interfaceMacAddrRaw)); +} + +CNetworkInterfaceLinux::~CNetworkInterfaceLinux(void) = default; + +bool CNetworkInterfaceLinux::IsEnabled() const +{ + struct ifreq ifr; + strcpy(ifr.ifr_name, m_interfaceName.c_str()); + if (ioctl(m_network->GetSocket(), SIOCGIFFLAGS, &ifr) < 0) + return false; + + return ((ifr.ifr_flags & IFF_UP) == IFF_UP); +} + +bool CNetworkInterfaceLinux::IsConnected() const +{ + struct ifreq ifr; + int zero = 0; + memset(&ifr,0,sizeof(struct ifreq)); + strcpy(ifr.ifr_name, m_interfaceName.c_str()); + if (ioctl(m_network->GetSocket(), SIOCGIFFLAGS, &ifr) < 0) + return false; + + // ignore loopback + int iRunning = ( (ifr.ifr_flags & IFF_RUNNING) && (!(ifr.ifr_flags & IFF_LOOPBACK))); + + if (ioctl(m_network->GetSocket(), SIOCGIFADDR, &ifr) < 0) + return false; + + // return only interfaces which has ip address + return iRunning && (0 != memcmp(ifr.ifr_addr.sa_data+sizeof(short), &zero, sizeof(int))); +} + +std::string CNetworkInterfaceLinux::GetMacAddress() const +{ + return m_interfaceMacAdr; +} + +void CNetworkInterfaceLinux::GetMacAddressRaw(char rawMac[6]) const +{ + memcpy(rawMac, m_interfaceMacAddrRaw, 6); +} + +std::string CNetworkInterfaceLinux::GetCurrentIPAddress(void) const +{ + std::string result; + + struct ifreq ifr; + strcpy(ifr.ifr_name, m_interfaceName.c_str()); + ifr.ifr_addr.sa_family = AF_INET; + if (ioctl(m_network->GetSocket(), SIOCGIFADDR, &ifr) >= 0) + { + result = inet_ntoa((*((struct sockaddr_in *)&ifr.ifr_addr)).sin_addr); + } + + return result; +} + +std::string CNetworkInterfaceLinux::GetCurrentNetmask(void) const +{ + std::string result; + + struct ifreq ifr; + strcpy(ifr.ifr_name, m_interfaceName.c_str()); + ifr.ifr_addr.sa_family = AF_INET; + if (ioctl(m_network->GetSocket(), SIOCGIFNETMASK, &ifr) >= 0) + { + result = inet_ntoa((*((struct sockaddr_in*)&ifr.ifr_addr)).sin_addr); + } + + return result; +} + +std::string CNetworkInterfaceLinux::GetCurrentDefaultGateway(void) const +{ + std::string result; + +#if defined(TARGET_DARWIN) + FILE* pipe = popen("echo \"show State:/Network/Global/IPv4\" | scutil | grep Router", "r"); + usleep(100000); + if (pipe) + { + std::string tmpStr; + char buffer[256] = {'\0'}; + if (fread(buffer, sizeof(char), sizeof(buffer), pipe) > 0 && !ferror(pipe)) + { + tmpStr = buffer; + if (tmpStr.length() >= 11) + result = tmpStr.substr(11); + } + pclose(pipe); + } + if (result.empty()) + CLog::Log(LOGWARNING, "Unable to determine gateway"); +#elif defined(TARGET_FREEBSD) + size_t needed; + int mib[6]; + char *buf, *next, *lim; + char line[16]; + struct rt_msghdr *rtm; + struct sockaddr *sa; + struct sockaddr_in *sockin; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = 0; + mib[4] = NET_RT_DUMP; + mib[5] = 0; + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + return result; + + if ((buf = (char *)malloc(needed)) == NULL) + return result; + + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { + free(buf); + return result; + } + + lim = buf + needed; + for (next = buf; next < lim; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; + sa = (struct sockaddr *)(rtm + 1); + sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa); + sockin = (struct sockaddr_in *)sa; + if (inet_ntop(AF_INET, &sockin->sin_addr.s_addr, + line, sizeof(line)) == NULL) { + free(buf); + return result; + } + result = line; + break; + } + free(buf); +#else + FILE* fp = fopen("/proc/net/route", "r"); + if (!fp) + { + // TBD: Error + return result; + } + + char* line = NULL; + char iface[16]; + char dst[128]; + char gateway[128]; + size_t linel = 0; + int n; + int linenum = 0; + while (getdelim(&line, &linel, '\n', fp) > 0) + { + // skip first two lines + if (linenum++ < 1) + continue; + + // search where the word begins + n = sscanf(line, "%15s %127s %127s", + iface, dst, gateway); + + if (n < 3) + continue; + + if (strcmp(iface, m_interfaceName.c_str()) == 0 && + strcmp(dst, "00000000") == 0 && + strcmp(gateway, "00000000") != 0) + { + unsigned char gatewayAddr[4]; + int len = CNetworkBase::ParseHex(gateway, gatewayAddr); + if (len == 4) + { + struct in_addr in; + in.s_addr = (gatewayAddr[0] << 24) | (gatewayAddr[1] << 16) | + (gatewayAddr[2] << 8) | (gatewayAddr[3]); + result = inet_ntoa(in); + break; + } + } + } + free(line); + fclose(fp); +#endif + + return result; +} + +CNetworkLinux::CNetworkLinux() + : CNetworkBase() +{ + m_sock = socket(AF_INET, SOCK_DGRAM, 0); + queryInterfaceList(); +} + +CNetworkLinux::~CNetworkLinux(void) +{ + if (m_sock != -1) + close(CNetworkLinux::m_sock); + + std::vector::iterator it = m_interfaces.begin(); + while(it != m_interfaces.end()) + { + CNetworkInterface* nInt = *it; + delete nInt; + it = m_interfaces.erase(it); + } +} + +std::vector& CNetworkLinux::GetInterfaceList(void) +{ + return m_interfaces; +} + +//! @bug +//! Overwrite the GetFirstConnectedInterface and requery +//! the interface list if no connected device is found +//! this fixes a bug when no network is available after first start of xbmc +//! and the interface comes up during runtime +CNetworkInterface* CNetworkLinux::GetFirstConnectedInterface(void) +{ + CNetworkInterface *pNetIf=CNetworkBase::GetFirstConnectedInterface(); + + // no connected Interfaces found? - requeryInterfaceList + if (!pNetIf) + { + CLog::Log(LOGDEBUG,"%s no connected interface found - requery list",__FUNCTION__); + queryInterfaceList(); + //retry finding a connected if + pNetIf = CNetworkBase::GetFirstConnectedInterface(); + } + + return pNetIf; +} + + +void CNetworkLinux::GetMacAddress(const std::string& interfaceName, char rawMac[6]) +{ + memset(rawMac, 0, 6); +#if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) + +#if !defined(IFT_ETHER) +#define IFT_ETHER 0x6/* Ethernet CSMACD */ +#endif + const struct sockaddr_dl* dlAddr = NULL; + const uint8_t * base = NULL; + // Query the list of interfaces. + struct ifaddrs *list; + struct ifaddrs *interface; + + if( getifaddrs(&list) < 0 ) + { + return; + } + + for(interface = list; interface != NULL; interface = interface->ifa_next) + { + if(interfaceName == interface->ifa_name) + { + if ( (interface->ifa_addr->sa_family == AF_LINK) && (((const struct sockaddr_dl *) interface->ifa_addr)->sdl_type == IFT_ETHER) ) + { + dlAddr = (const struct sockaddr_dl *) interface->ifa_addr; + base = (const uint8_t *) &dlAddr->sdl_data[dlAddr->sdl_nlen]; + + if( dlAddr->sdl_alen > 5 ) + { + memcpy(rawMac, base, 6); + } + } + break; + } + } + + freeifaddrs(list); + +#else + + struct ifreq ifr; + strcpy(ifr.ifr_name, interfaceName.c_str()); + if (ioctl(GetSocket(), SIOCGIFHWADDR, &ifr) >= 0) + { + memcpy(rawMac, ifr.ifr_hwaddr.sa_data, 6); + } +#endif +} + +void CNetworkLinux::queryInterfaceList() +{ + char macAddrRaw[6]; + m_interfaces.clear(); + +#if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) + + // Query the list of interfaces. + struct ifaddrs *list; + if (getifaddrs(&list) < 0) + return; + + struct ifaddrs *cur; + for(cur = list; cur != NULL; cur = cur->ifa_next) + { + if(cur->ifa_addr->sa_family != AF_INET) + continue; + + GetMacAddress(cur->ifa_name, macAddrRaw); + + // only add interfaces with non-zero mac addresses + if (macAddrRaw[0] || macAddrRaw[1] || macAddrRaw[2] || macAddrRaw[3] || macAddrRaw[4] || macAddrRaw[5]) + // Add the interface. + m_interfaces.push_back(new CNetworkInterfaceLinux(this, cur->ifa_name, macAddrRaw)); + } + + freeifaddrs(list); + +#else + FILE* fp = fopen("/proc/net/dev", "r"); + if (!fp) + { + // TBD: Error + return; + } + + char* line = NULL; + size_t linel = 0; + int n; + char* p; + int linenum = 0; + while (getdelim(&line, &linel, '\n', fp) > 0) + { + // skip first two lines + if (linenum++ < 2) + continue; + + // search where the word begins + p = line; + while (isspace(*p)) + ++p; + + // read word until : + n = strcspn(p, ": \t"); + p[n] = 0; + + // save the result + std::string interfaceName = p; + GetMacAddress(interfaceName, macAddrRaw); + + // only add interfaces with non-zero mac addresses + if (macAddrRaw[0] || macAddrRaw[1] || macAddrRaw[2] || macAddrRaw[3] || macAddrRaw[4] || macAddrRaw[5]) + m_interfaces.push_back(new CNetworkInterfaceLinux(this, interfaceName, macAddrRaw)); + } + free(line); + fclose(fp); +#endif +} + +std::vector CNetworkLinux::GetNameServers(void) +{ + std::vector result; + +#if defined(TARGET_DARWIN) + FILE* pipe = popen("scutil --dns | grep \"nameserver\" | tail -n2", "r"); + usleep(100000); + if (pipe) + { + std::vector tmpStr; + char buffer[256] = {'\0'}; + if (fread(buffer, sizeof(char), sizeof(buffer), pipe) > 0 && !ferror(pipe)) + { + tmpStr = StringUtils::Split(buffer, "\n"); + for (unsigned int i = 0; i < tmpStr.size(); i ++) + { + // result looks like this - > ' nameserver[0] : 192.168.1.1' + // 2 blank spaces + 13 in 'nameserver[0]' + blank + ':' + blank == 18 :) + if (tmpStr[i].length() >= 18) + result.push_back(tmpStr[i].substr(18)); + } + } + pclose(pipe); + } + if (result.empty()) + CLog::Log(LOGWARNING, "Unable to determine nameserver"); +#elif defined(TARGET_ANDROID) + char nameserver[PROP_VALUE_MAX]; + + if (__system_property_get("net.dns1",nameserver)) + result.push_back(nameserver); + if (__system_property_get("net.dns2",nameserver)) + result.push_back(nameserver); + if (__system_property_get("net.dns3",nameserver)) + result.push_back(nameserver); + + if (!result.size()) + CLog::Log(LOGWARNING, "Unable to determine nameserver"); +#else + res_init(); + + for (int i = 0; i < _res.nscount; i ++) + { + std::string ns = inet_ntoa(_res.nsaddr_list[i].sin_addr); + result.push_back(ns); + } +#endif + return result; +} + +bool CNetworkLinux::PingHost(unsigned long remote_ip, unsigned int timeout_ms) +{ + char cmd_line [64]; + + struct in_addr host_ip; + host_ip.s_addr = remote_ip; + +#if defined (TARGET_DARWIN) || defined (TARGET_FREEBSD) + sprintf(cmd_line, "ping -c 1 -t %d %s", timeout_ms / 1000 + (timeout_ms % 1000) != 0, inet_ntoa(host_ip)); +#else + sprintf(cmd_line, "ping -c 1 -w %d %s", timeout_ms / 1000 + (timeout_ms % 1000) != 0, inet_ntoa(host_ip)); +#endif + + int status = -1; +#if !defined (TARGET_DARWIN_IOS) // no system calls allowed since ios11 + status = system (cmd_line); +#endif + int result = WIFEXITED(status) ? WEXITSTATUS(status) : -1; + + // http://linux.about.com/od/commands/l/blcmdl8_ping.htm ; + // 0 reply + // 1 no reply + // else some error + + if (result < 0 || result > 1) + CLog::Log(LOGERROR, "Ping fail : status = %d, errno = %d : '%s'", status, errno, cmd_line); + + return result == 0; +} + +#if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) +bool CNetworkInterfaceLinux::GetHostMacAddress(unsigned long host_ip, std::string& mac) const +{ + bool ret = false; + size_t needed; + char *buf, *next; + struct rt_msghdr *rtm; + struct sockaddr_inarp *sin; + struct sockaddr_dl *sdl; + int mib[6]; + + mac = ""; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET; + mib[4] = NET_RT_FLAGS; + mib[5] = RTF_LLINFO; + + if (sysctl(mib, ARRAY_SIZE(mib), NULL, &needed, NULL, 0) == 0) + { + buf = (char*)malloc(needed); + if (buf) + { + if (sysctl(mib, ARRAY_SIZE(mib), buf, &needed, NULL, 0) == 0) + { + for (next = buf; next < buf + needed; next += rtm->rtm_msglen) + { + + rtm = (struct rt_msghdr *)next; + sin = (struct sockaddr_inarp *)(rtm + 1); + sdl = (struct sockaddr_dl *)(sin + 1); + + if (host_ip != sin->sin_addr.s_addr || sdl->sdl_alen < 6) + continue; + + u_char *cp = (u_char*)LLADDR(sdl); + + mac = StringUtils::Format("%02X:%02X:%02X:%02X:%02X:%02X", + cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); + ret = true; + break; + } + } + free(buf); + } + } + return ret; +} +#else +bool CNetworkInterfaceLinux::GetHostMacAddress(unsigned long host_ip, std::string& mac) const +{ + struct arpreq areq; + struct sockaddr_in* sin; + + memset(&areq, 0x0, sizeof(areq)); + + sin = (struct sockaddr_in *) &areq.arp_pa; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = host_ip; + + sin = (struct sockaddr_in *) &areq.arp_ha; + sin->sin_family = ARPHRD_ETHER; + + strncpy(areq.arp_dev, m_interfaceName.c_str(), sizeof(areq.arp_dev)); + areq.arp_dev[sizeof(areq.arp_dev)-1] = '\0'; + + int result = ioctl (m_network->GetSocket(), SIOCGARP, (caddr_t) &areq); + + if (result != 0) + { +// CLog::Log(LOGERROR, "%s - GetHostMacAddress/ioctl failed with errno (%d)", __FUNCTION__, errno); + return false; + } + + struct sockaddr* res = &areq.arp_ha; + mac = StringUtils::Format("%02X:%02X:%02X:%02X:%02X:%02X", + (uint8_t) res->sa_data[0], (uint8_t) res->sa_data[1], (uint8_t) res->sa_data[2], + (uint8_t) res->sa_data[3], (uint8_t) res->sa_data[4], (uint8_t) res->sa_data[5]); + + for (int i=0; i<6; ++i) + if (res->sa_data[i]) + return true; + + return false; +} +#endif diff --git a/xbmc/platform/posix/network/NetworkLinux.h b/xbmc/platform/posix/network/NetworkLinux.h new file mode 100644 index 0000000000..13d87076ae --- /dev/null +++ b/xbmc/platform/posix/network/NetworkLinux.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include +#include "network/Network.h" + +class CNetworkLinux; + +class CNetworkInterfaceLinux : public CNetworkInterface +{ +public: + CNetworkInterfaceLinux(CNetworkLinux* network, std::string interfaceName, char interfaceMacAddrRaw[6]); + ~CNetworkInterfaceLinux(void) override; + + bool IsEnabled(void) const override; + bool IsConnected(void) const override; + + std::string GetMacAddress(void) const override; + void GetMacAddressRaw(char rawMac[6]) const override; + + bool GetHostMacAddress(unsigned long host, std::string& mac) const override; + + std::string GetCurrentIPAddress() const override; + std::string GetCurrentNetmask() const override; + std::string GetCurrentDefaultGateway(void) const override; + +private: + std::string m_interfaceName; + std::string m_interfaceMacAdr; + char m_interfaceMacAddrRaw[6]; + CNetworkLinux* m_network; +}; + +class CNetworkLinux : public CNetworkBase +{ +public: + CNetworkLinux(); + ~CNetworkLinux(void) override; + + // Return the list of interfaces + std::vector& GetInterfaceList(void) override; + CNetworkInterface* GetFirstConnectedInterface(void) override; + + // Ping remote host + bool PingHost(unsigned long host, unsigned int timeout_ms = 2000) override; + + // Get/set the nameserver(s) + std::vector GetNameServers(void) override; + + friend class CNetworkInterfaceLinux; + +private: + int GetSocket() { return m_sock; } + void GetMacAddress(const std::string& interfaceName, char macAddrRaw[6]); + void queryInterfaceList(); + std::vector m_interfaces; + int m_sock; +}; + +using CNetwork = CNetworkLinux; + -- cgit v1.2.3