diff options
Diffstat (limited to 'xbmc/platform/freebsd')
-rw-r--r-- | xbmc/platform/freebsd/CMakeLists.txt | 28 | ||||
-rw-r--r-- | xbmc/platform/freebsd/CPUInfoFreebsd.cpp | 268 | ||||
-rw-r--r-- | xbmc/platform/freebsd/CPUInfoFreebsd.h | 24 | ||||
-rw-r--r-- | xbmc/platform/freebsd/MemUtils.cpp | 83 | ||||
-rw-r--r-- | xbmc/platform/freebsd/OptionalsReg.cpp | 23 | ||||
-rw-r--r-- | xbmc/platform/freebsd/OptionalsReg.h | 18 | ||||
-rw-r--r-- | xbmc/platform/freebsd/PlatformFreebsd.cpp | 124 | ||||
-rw-r--r-- | xbmc/platform/freebsd/PlatformFreebsd.h | 26 | ||||
-rw-r--r-- | xbmc/platform/freebsd/network/CMakeLists.txt | 4 | ||||
-rw-r--r-- | xbmc/platform/freebsd/network/NetworkFreebsd.cpp | 247 | ||||
-rw-r--r-- | xbmc/platform/freebsd/network/NetworkFreebsd.h | 40 |
11 files changed, 885 insertions, 0 deletions
diff --git a/xbmc/platform/freebsd/CMakeLists.txt b/xbmc/platform/freebsd/CMakeLists.txt new file mode 100644 index 0000000..9b8782f --- /dev/null +++ b/xbmc/platform/freebsd/CMakeLists.txt @@ -0,0 +1,28 @@ +set(SOURCES ../linux/AppParamParserLinux.cpp + CPUInfoFreebsd.cpp + OptionalsReg.cpp + ../linux/OptionalsReg.cpp + ../linux/TimeUtils.cpp + MemUtils.cpp + PlatformFreebsd.cpp) + +set(HEADERS ../linux/AppParamParserLinux.cpp + CPUInfoFreebsd.h + OptionalsReg.h + ../linux/OptionalsReg.h + ../linux/TimeUtils.h + PlatformFreebsd.h) + +if(ALSA_FOUND) + list(APPEND SOURCES ../linux/FDEventMonitor.cpp) + list(APPEND HEADERS ../linux/FDEventMonitor.h) +endif() + +if(DBUS_FOUND) + list(APPEND SOURCES ../linux/DBusMessage.cpp + ../linux/DBusUtil.cpp) + list(APPEND HEADERS ../linux/DBusMessage.h + ../linux/DBusUtil.h) +endif() + +core_add_library(freebsdsupport) diff --git a/xbmc/platform/freebsd/CPUInfoFreebsd.cpp b/xbmc/platform/freebsd/CPUInfoFreebsd.cpp new file mode 100644 index 0000000..5128a72 --- /dev/null +++ b/xbmc/platform/freebsd/CPUInfoFreebsd.cpp @@ -0,0 +1,268 @@ +/* + * 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 "CPUInfoFreebsd.h" + +#include "utils/Temperature.h" +#include "utils/log.h" + +#include <array> +#include <vector> + +// clang-format off +/* sys/types.h must be included early, esp. before sysy/systl.h, otherwise: + /usr/include/sys/sysctl.h:1117:25: error: unknown type name 'u_int' */ + +#include <sys/types.h> +// clang-format on + +#if defined(__i386__) || defined(__x86_64__) +#include <cpuid.h> +#elif __has_include(<sys/auxv.h>) +#include <sys/auxv.h> +#endif + +#include <sys/resource.h> +#include <sys/sysctl.h> + +namespace +{ + +struct CpuData +{ +public: + std::size_t GetActiveTime() const { return state[CP_USER] + state[CP_NICE] + state[CP_SYS]; } + + std::size_t GetIdleTime() const { return state[CP_INTR] + state[CP_IDLE]; } + + std::size_t GetTotalTime() const { return GetActiveTime() + GetIdleTime(); } + + std::size_t state[CPUSTATES]; +}; + +} // namespace + +std::shared_ptr<CCPUInfo> CCPUInfo::GetCPUInfo() +{ + return std::make_shared<CCPUInfoFreebsd>(); +} + +CCPUInfoFreebsd::CCPUInfoFreebsd() +{ + int count = 0; + size_t countLength = sizeof(count); + if (sysctlbyname("hw.ncpu", &count, &countLength, nullptr, 0) == 0) + m_cpuCount = count; + else + m_cpuCount = 1; + + std::array<char, 512> cpuModel; + size_t length = cpuModel.size(); + if (sysctlbyname("hw.model", cpuModel.data(), &length, nullptr, 0) == 0) + m_cpuModel = cpuModel.data(); + + for (int i = 0; i < m_cpuCount; i++) + { + CoreInfo core; + core.m_id = i; + m_cores.emplace_back(core); + } +#if defined(__i386__) || defined(__x86_64__) + uint32_t eax, ebx, ecx, edx; + + m_cpuVendor.clear(); + + if (__get_cpuid(CPUID_INFOTYPE_MANUFACTURER, &eax, &ebx, &ecx, &edx)) + { + m_cpuVendor.append(reinterpret_cast<const char*>(&ebx), 4); + m_cpuVendor.append(reinterpret_cast<const char*>(&edx), 4); + m_cpuVendor.append(reinterpret_cast<const char*>(&ecx), 4); + } + + if (__get_cpuid(CPUID_INFOTYPE_EXTENDED_IMPLEMENTED, &eax, &ebx, &ecx, &edx)) + { + if (eax >= CPUID_INFOTYPE_PROCESSOR_3) + { + m_cpuModel.clear(); + + if (__get_cpuid(CPUID_INFOTYPE_PROCESSOR_1, &eax, &ebx, &ecx, &edx)) + { + m_cpuModel.append(reinterpret_cast<const char*>(&eax), 4); + m_cpuModel.append(reinterpret_cast<const char*>(&ebx), 4); + m_cpuModel.append(reinterpret_cast<const char*>(&ecx), 4); + m_cpuModel.append(reinterpret_cast<const char*>(&edx), 4); + } + + if (__get_cpuid(CPUID_INFOTYPE_PROCESSOR_2, &eax, &ebx, &ecx, &edx)) + { + m_cpuModel.append(reinterpret_cast<const char*>(&eax), 4); + m_cpuModel.append(reinterpret_cast<const char*>(&ebx), 4); + m_cpuModel.append(reinterpret_cast<const char*>(&ecx), 4); + m_cpuModel.append(reinterpret_cast<const char*>(&edx), 4); + } + + if (__get_cpuid(CPUID_INFOTYPE_PROCESSOR_3, &eax, &ebx, &ecx, &edx)) + { + m_cpuModel.append(reinterpret_cast<const char*>(&eax), 4); + m_cpuModel.append(reinterpret_cast<const char*>(&ebx), 4); + m_cpuModel.append(reinterpret_cast<const char*>(&ecx), 4); + m_cpuModel.append(reinterpret_cast<const char*>(&edx), 4); + } + } + } + + m_cpuModel = m_cpuModel.substr(0, m_cpuModel.find(char(0))); // remove extra null terminations + + if (__get_cpuid(CPUID_INFOTYPE_STANDARD, &eax, &eax, &ecx, &edx)) + { + if (edx & CPUID_00000001_EDX_MMX) + m_cpuFeatures |= CPU_FEATURE_MMX; + + // Set MMX2 when SSE is present as SSE is a superset of MMX2 and Intel doesn't set the MMX2 cap + if (edx & CPUID_00000001_EDX_SSE) + m_cpuFeatures |= (CPU_FEATURE_SSE | CPU_FEATURE_MMX2); + + if (edx & CPUID_00000001_EDX_SSE2) + m_cpuFeatures |= CPU_FEATURE_SSE2; + + if (ecx & CPUID_00000001_ECX_SSE3) + m_cpuFeatures |= CPU_FEATURE_SSE3; + + if (ecx & CPUID_00000001_ECX_SSSE3) + m_cpuFeatures |= CPU_FEATURE_SSSE3; + + if (ecx & CPUID_00000001_ECX_SSE4) + m_cpuFeatures |= CPU_FEATURE_SSE4; + + if (ecx & CPUID_00000001_ECX_SSE42) + m_cpuFeatures |= CPU_FEATURE_SSE42; + } + + if (__get_cpuid(CPUID_INFOTYPE_EXTENDED_IMPLEMENTED, &eax, &eax, &ecx, &edx)) + { + if (eax >= CPUID_INFOTYPE_EXTENDED) + { + if (edx & CPUID_80000001_EDX_MMX) + m_cpuFeatures |= CPU_FEATURE_MMX; + + if (edx & CPUID_80000001_EDX_MMX2) + m_cpuFeatures |= CPU_FEATURE_MMX2; + + if (edx & CPUID_80000001_EDX_3DNOW) + m_cpuFeatures |= CPU_FEATURE_3DNOW; + + if (edx & CPUID_80000001_EDX_3DNOWEXT) + m_cpuFeatures |= CPU_FEATURE_3DNOWEXT; + } + } +#endif + +#if defined(HAS_NEON) +#if defined(__ARM_NEON) + m_cpuFeatures |= CPU_FEATURE_NEON; +#elif __has_include(<sys/auxv.h>) + unsigned long hwcap = 0; + elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); + if (hwcap & HWCAP_NEON) + m_cpuFeatures |= CPU_FEATURE_NEON; +#endif +#endif +} + +int CCPUInfoFreebsd::GetUsedPercentage() +{ + if (!m_nextUsedReadTime.IsTimePast()) + return m_lastUsedPercentage; + + size_t len = sizeof(long); + + if (sysctlbyname("kern.cp_times", nullptr, &len, nullptr, 0) != 0) + return false; + + std::vector<long> cptimes(len); + size_t cptimesLength = cptimes.size(); + if (sysctlbyname("kern.cp_times", cptimes.data(), &cptimesLength, nullptr, 0) != 0) + return false; + + size_t activeTime{0}; + size_t idleTime{0}; + size_t totalTime{0}; + + std::vector<CpuData> cpuData; + + for (int i = 0; i < m_cpuCount; i++) + { + CpuData info; + + for (size_t state = 0; state < CPUSTATES; state++) + { + info.state[state] = cptimes[i * CPUSTATES + state]; + } + + activeTime += info.GetActiveTime(); + idleTime += info.GetIdleTime(); + totalTime += info.GetTotalTime(); + + cpuData.emplace_back(info); + } + + activeTime -= m_activeTime; + idleTime -= m_idleTime; + totalTime -= m_totalTime; + + m_activeTime += activeTime; + m_idleTime += idleTime; + m_totalTime += totalTime; + + m_lastUsedPercentage = activeTime * 100.0f / totalTime; + m_nextUsedReadTime.Set(MINIMUM_TIME_BETWEEN_READS); + + for (size_t core = 0; core < cpuData.size(); core++) + { + auto activeTime = cpuData[core].GetActiveTime() - m_cores[core].m_activeTime; + auto idleTime = cpuData[core].GetIdleTime() - m_cores[core].m_idleTime; + auto totalTime = cpuData[core].GetTotalTime() - m_cores[core].m_totalTime; + + m_cores[core].m_usagePercent = activeTime * 100.0 / totalTime; + + m_cores[core].m_activeTime += activeTime; + m_cores[core].m_idleTime += idleTime; + m_cores[core].m_totalTime += totalTime; + } + + return static_cast<int>(m_lastUsedPercentage); +} + +float CCPUInfoFreebsd::GetCPUFrequency() +{ + int hz = 0; + size_t len = sizeof(hz); + if (sysctlbyname("dev.cpu.0.freq", &hz, &len, nullptr, 0) != 0) + hz = 0; + + return static_cast<float>(hz); +} + + +bool CCPUInfoFreebsd::GetTemperature(CTemperature& temperature) +{ + if (CheckUserTemperatureCommand(temperature)) + return true; + + int value; + size_t len = sizeof(value); + + /* Temperature is in Kelvin * 10 */ + if (sysctlbyname("dev.cpu.0.temperature", &value, &len, nullptr, 0) != 0) + return false; + + temperature = CTemperature::CreateFromKelvin(static_cast<double>(value) / 10.0); + temperature.SetValid(true); + + return true; +} diff --git a/xbmc/platform/freebsd/CPUInfoFreebsd.h b/xbmc/platform/freebsd/CPUInfoFreebsd.h new file mode 100644 index 0000000..f1743ce --- /dev/null +++ b/xbmc/platform/freebsd/CPUInfoFreebsd.h @@ -0,0 +1,24 @@ +/* + * 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 "utils/Temperature.h" + +#include "platform/posix/CPUInfoPosix.h" + +class CCPUInfoFreebsd : public CCPUInfoPosix +{ +public: + CCPUInfoFreebsd(); + ~CCPUInfoFreebsd() = default; + + int GetUsedPercentage() override; + float GetCPUFrequency() override; + bool GetTemperature(CTemperature& temperature) override; +}; diff --git a/xbmc/platform/freebsd/MemUtils.cpp b/xbmc/platform/freebsd/MemUtils.cpp new file mode 100644 index 0000000..de3e42c --- /dev/null +++ b/xbmc/platform/freebsd/MemUtils.cpp @@ -0,0 +1,83 @@ +/* + * 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 "utils/MemUtils.h" + +#include <array> +#include <cstdlib> +#include <cstring> +#include <stdio.h> + +#include <unistd.h> /* FreeBSD can't write standalone headers */ +#include <sys/sysctl.h> /* FreeBSD can't write standalone headers */ +#include <sys/types.h> + +namespace KODI +{ +namespace MEMORY +{ + +void* AlignedMalloc(size_t s, size_t alignTo) +{ + void* p; + posix_memalign(&p, alignTo, s); + + return p; +} + +void AlignedFree(void* p) +{ + free(p); +} + +void GetMemoryStatus(MemoryStatus* buffer) +{ + if (!buffer) + return; + + /* sysctl hw.physmem */ + size_t len = 0; + + /* physmem */ + size_t physmem = 0; + len = sizeof(physmem); + if (sysctlbyname("hw.physmem", &physmem, &len, NULL, 0) == 0) + { + buffer->totalPhys = physmem; + } + + /* pagesize */ + size_t pagesize = 0; + len = sizeof(pagesize); + if (sysctlbyname("hw.pagesize", &pagesize, &len, NULL, 0) != 0) + pagesize = 4096; + + /* mem_inactive */ + size_t mem_inactive = 0; + len = sizeof(mem_inactive); + if (sysctlbyname("vm.stats.vm.v_inactive_count", &mem_inactive, &len, NULL, 0) == 0) + mem_inactive *= pagesize; + + /* mem_cache */ + size_t mem_cache = 0; + len = sizeof(mem_cache); + if (sysctlbyname("vm.stats.vm.v_cache_count", &mem_cache, &len, NULL, 0) == 0) + mem_cache *= pagesize; + + /* mem_free */ + size_t mem_free = 0; + len = sizeof(mem_free); + if (sysctlbyname("vm.stats.vm.v_free_count", &mem_free, &len, NULL, 0) == 0) + mem_free *= pagesize; + + /* mem_avail = mem_inactive + mem_cache + mem_free */ + buffer->availPhys = mem_inactive + mem_cache + mem_free; +} + +} +} diff --git a/xbmc/platform/freebsd/OptionalsReg.cpp b/xbmc/platform/freebsd/OptionalsReg.cpp new file mode 100644 index 0000000..ed414f1 --- /dev/null +++ b/xbmc/platform/freebsd/OptionalsReg.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2005-2019 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 "OptionalsReg.h" + + +//----------------------------------------------------------------------------- +// OSS +//----------------------------------------------------------------------------- + +#ifdef HAS_OSS +#include "cores/AudioEngine/Sinks/AESinkOSS.h" +bool OPTIONALS::OSSRegister() +{ + CAESinkOSS::Register(); + return true; +} +#endif diff --git a/xbmc/platform/freebsd/OptionalsReg.h b/xbmc/platform/freebsd/OptionalsReg.h new file mode 100644 index 0000000..36837d0 --- /dev/null +++ b/xbmc/platform/freebsd/OptionalsReg.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2005-2019 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 + +//----------------------------------------------------------------------------- +// OSS +//----------------------------------------------------------------------------- + +namespace OPTIONALS +{ +bool OSSRegister(); +} diff --git a/xbmc/platform/freebsd/PlatformFreebsd.cpp b/xbmc/platform/freebsd/PlatformFreebsd.cpp new file mode 100644 index 0000000..b65501b --- /dev/null +++ b/xbmc/platform/freebsd/PlatformFreebsd.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016-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 "PlatformFreebsd.h" + +#include "utils/StringUtils.h" + +#include "platform/freebsd/OptionalsReg.h" +#include "platform/linux/powermanagement/LinuxPowerSyscall.h" + +// clang-format off +#if defined(HAS_GLES) +#if defined(HAVE_WAYLAND) +#include "windowing/wayland/WinSystemWaylandEGLContextGLES.h" +#endif +#if defined(HAVE_X11) +#include "windowing/X11/WinSystemX11GLESContext.h" +#endif +#if defined(HAVE_GBM) +#include "windowing/gbm/WinSystemGbmGLESContext.h" +#endif +#endif + +#if defined(HAS_GL) +#if defined(HAVE_WAYLAND) +#include "windowing/wayland/WinSystemWaylandEGLContextGL.h" +#endif +#if defined(HAVE_X11) +#include "windowing/X11/WinSystemX11GLContext.h" +#endif +#if defined(HAVE_GBM) +#include "windowing/gbm/WinSystemGbmGLContext.h" +#endif +#endif +// clang-format on + +#include <cstdlib> + +CPlatform* CPlatform::CreateInstance() +{ + return new CPlatformFreebsd(); +} + +bool CPlatformFreebsd::InitStageOne() +{ + if (!CPlatformPosix::InitStageOne()) + return false; + + setenv("OS", "Linux", true); // for python scripts that check the OS + +#if defined(HAS_GLES) +#if defined(HAVE_WAYLAND) + KODI::WINDOWING::WAYLAND::CWinSystemWaylandEGLContextGLES::Register(); +#endif +#if defined(HAVE_X11) + KODI::WINDOWING::X11::CWinSystemX11GLESContext::Register(); +#endif +#if defined(HAVE_GBM) + KODI::WINDOWING::GBM::CWinSystemGbmGLESContext::Register(); +#endif +#endif + +#if defined(HAS_GL) +#if defined(HAVE_WAYLAND) + KODI::WINDOWING::WAYLAND::CWinSystemWaylandEGLContextGL::Register(); +#endif +#if defined(HAVE_X11) + KODI::WINDOWING::X11::CWinSystemX11GLContext::Register(); +#endif +#if defined(HAVE_GBM) + KODI::WINDOWING::GBM::CWinSystemGbmGLContext::Register(); +#endif +#endif + + CLinuxPowerSyscall::Register(); + + std::string envSink; + if (getenv("KODI_AE_SINK")) + envSink = getenv("KODI_AE_SINK"); + + if (StringUtils::EqualsNoCase(envSink, "ALSA")) + { + OPTIONALS::ALSARegister(); + } + else if (StringUtils::EqualsNoCase(envSink, "PULSE")) + { + OPTIONALS::PulseAudioRegister(); + } + else if (StringUtils::EqualsNoCase(envSink, "OSS")) + { + OPTIONALS::OSSRegister(); + } + else if (StringUtils::EqualsNoCase(envSink, "SNDIO")) + { + OPTIONALS::SndioRegister(); + } + else if (StringUtils::EqualsNoCase(envSink, "ALSA+PULSE")) + { + OPTIONALS::ALSARegister(); + OPTIONALS::PulseAudioRegister(); + } + else + { + if (!OPTIONALS::PulseAudioRegister()) + { + if (!OPTIONALS::ALSARegister()) + { + if (!OPTIONALS::SndioRegister()) + { + OPTIONALS::OSSRegister(); + } + } + } + } + + m_lirc.reset(OPTIONALS::LircRegister()); + + return true; +} diff --git a/xbmc/platform/freebsd/PlatformFreebsd.h b/xbmc/platform/freebsd/PlatformFreebsd.h new file mode 100644 index 0000000..48a4151 --- /dev/null +++ b/xbmc/platform/freebsd/PlatformFreebsd.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016-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 "platform/linux/OptionalsReg.h" +#include "platform/posix/PlatformPosix.h" + +#include <memory> + +class CPlatformFreebsd : public CPlatformPosix +{ +public: + CPlatformFreebsd() = default; + ~CPlatformFreebsd() override = default; + + bool InitStageOne() override; + +private: + std::unique_ptr<OPTIONALS::CLircContainer, OPTIONALS::delete_CLircContainer> m_lirc; +}; diff --git a/xbmc/platform/freebsd/network/CMakeLists.txt b/xbmc/platform/freebsd/network/CMakeLists.txt new file mode 100644 index 0000000..25d8ee8 --- /dev/null +++ b/xbmc/platform/freebsd/network/CMakeLists.txt @@ -0,0 +1,4 @@ +set(SOURCES NetworkFreebsd.cpp) +set(HEADERS NetworkFreebsd.h) + +core_add_library(platform_freebsd_network) diff --git a/xbmc/platform/freebsd/network/NetworkFreebsd.cpp b/xbmc/platform/freebsd/network/NetworkFreebsd.cpp new file mode 100644 index 0000000..94a0a41 --- /dev/null +++ b/xbmc/platform/freebsd/network/NetworkFreebsd.cpp @@ -0,0 +1,247 @@ +/* + * 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 "NetworkFreebsd.h" + +#include "utils/StringUtils.h" +#include "utils/log.h" + +#include <array> +#include <errno.h> + +#include <arpa/inet.h> +#include <ifaddrs.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/route.h> +#include <netinet/if_ether.h> +#include <netinet/in.h> +#include <resolv.h> +#include <sys/sockio.h> +#include <sys/wait.h> + +CNetworkInterfaceFreebsd::CNetworkInterfaceFreebsd(CNetworkPosix* network, + std::string interfaceName, + char interfaceMacAddrRaw[6]) + : CNetworkInterfacePosix(network, interfaceName, interfaceMacAddrRaw) +{ +} + +std::string CNetworkInterfaceFreebsd::GetCurrentDefaultGateway() const +{ + std::string result; + + 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); + + return result; +} + +bool CNetworkInterfaceFreebsd::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; + constexpr std::array<int, 6> mib = { + CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO, + }; + + mac = ""; + + if (sysctl(mib.data(), mib.size(), nullptr, &needed, nullptr, 0) == 0) + { + buf = (char*)malloc(needed); + if (buf) + { + if (sysctl(mib.data(), mib.size(), buf, &needed, nullptr, 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; +} + +std::unique_ptr<CNetworkBase> CNetworkBase::GetNetwork() +{ + return std::make_unique<CNetworkFreebsd>(); +} + +CNetworkFreebsd::CNetworkFreebsd() : CNetworkPosix() +{ + queryInterfaceList(); +} + +void CNetworkFreebsd::GetMacAddress(const std::string& interfaceName, char rawMac[6]) +{ + memset(rawMac, 0, 6); + +#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); +} + +void CNetworkFreebsd::queryInterfaceList() +{ + char macAddrRaw[6]; + m_interfaces.clear(); + + // 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 CNetworkInterfaceFreebsd(this, cur->ifa_name, macAddrRaw)); + } + + freeifaddrs(list); +} + +std::vector<std::string> CNetworkFreebsd::GetNameServers() +{ + std::vector<std::string> result; + + 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); + } + + return result; +} + +bool CNetworkFreebsd::PingHost(unsigned long remote_ip, unsigned int timeout_ms) +{ + char cmd_line[64]; + + struct in_addr host_ip; + host_ip.s_addr = remote_ip; + + sprintf(cmd_line, "ping -c 1 -t %d %s", timeout_ms / 1000 + (timeout_ms % 1000) != 0, + inet_ntoa(host_ip)); + + int status = -1; + status = system(cmd_line); + 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 = {}, errno = {} : '{}'", status, errno, cmd_line); + + return result == 0; +} diff --git a/xbmc/platform/freebsd/network/NetworkFreebsd.h b/xbmc/platform/freebsd/network/NetworkFreebsd.h new file mode 100644 index 0000000..92b00d7 --- /dev/null +++ b/xbmc/platform/freebsd/network/NetworkFreebsd.h @@ -0,0 +1,40 @@ +/* + * 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 "platform/posix/network/NetworkPosix.h" + +#include <string> +#include <vector> + +class CNetworkInterfaceFreebsd : public CNetworkInterfacePosix +{ +public: + CNetworkInterfaceFreebsd(CNetworkPosix* network, + std::string interfaceName, + char interfaceMacAddrRaw[6]); + ~CNetworkInterfaceFreebsd() override = default; + + std::string GetCurrentDefaultGateway() const override; + bool GetHostMacAddress(unsigned long host, std::string& mac) const override; +}; + +class CNetworkFreebsd : public CNetworkPosix +{ +public: + CNetworkFreebsd(); + ~CNetworkFreebsd() override = default; + + bool PingHost(unsigned long host, unsigned int timeout_ms = 2000) override; + std::vector<std::string> GetNameServers() override; + +private: + void GetMacAddress(const std::string& interfaceName, char macAddrRaw[6]) override; + void queryInterfaceList() override; +}; |