mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
This is the start of the implementing for the Linux platform. I aim to make this as similar to the Windows platform as possible, although due to the fundamental difference in the two OS's, there will be things that need to be different. As such, I will be using the Windows platform files as a base, and reimplementing the functions with Linux equivalents. I am sure this will have bugs, which by my best attempt will be fixed when found.
363 lines
11 KiB
C++
363 lines
11 KiB
C++
// Copyright 2020 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "internal/platform/implementation/linux/utils.h"
|
|
|
|
// Standard C/C++ headers
|
|
#include <cerrno>
|
|
#include <codecvt>
|
|
#include <cstdint>
|
|
#include <exception>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
// Third party headers
|
|
#include "absl/strings/ascii.h"
|
|
#include "absl/strings/str_cat.h"
|
|
#include "absl/strings/str_format.h"
|
|
|
|
// Nearby connections headers
|
|
#include "absl/strings/string_view.h"
|
|
#include "internal/platform/bluetooth_utils.h"
|
|
#include "internal/platform/byte_array.h"
|
|
#include "internal/platform/implementation/crypto.h"
|
|
#include "internal/platform/logging.h"
|
|
#include "internal/platform/uuid.h"
|
|
|
|
// Linux headers
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <ifaddrs.h>
|
|
#include <netdb.h>
|
|
|
|
namespace nearby {
|
|
namespace linux {
|
|
namespace {
|
|
|
|
std::string uint64_to_mac_address_string(uint64_t bluetoothAddress) {
|
|
std::string buffer = absl::StrFormat(
|
|
"%02llx:%02llx:%02llx:%02llx:%02llx:%02llx", bluetoothAddress >> 40,
|
|
(bluetoothAddress >> 32) & 0xff, (bluetoothAddress >> 24) & 0xff,
|
|
(bluetoothAddress >> 16) & 0xff, (bluetoothAddress >> 8) & 0xff,
|
|
bluetoothAddress & 0xff);
|
|
|
|
return absl::AsciiStrToUpper(buffer);
|
|
}
|
|
|
|
uint64_t mac_address_string_to_uint64(absl::string_view mac_address) {
|
|
ByteArray mac_address_array = BluetoothUtils::FromString(mac_address);
|
|
uint64_t mac_address_uint64 = 0;
|
|
for (int i = 0; i < mac_address_array.size(); i++) {
|
|
mac_address_uint64 <<= 8;
|
|
mac_address_uint64 |= static_cast<uint8_t>(
|
|
static_cast<unsigned char>(*(mac_address_array.data() + i)));
|
|
}
|
|
return mac_address_uint64;
|
|
}
|
|
|
|
std::string ipaddr_4bytes_to_dotdecimal_string(
|
|
absl::string_view ipaddr_4bytes) {
|
|
|
|
union addrs {
|
|
in_addr_t addr;
|
|
uint8_t bits[4];
|
|
} address;
|
|
|
|
address.bits[0] = ipaddr_4bytes[0];
|
|
address.bits[1] = ipaddr_4bytes[1];
|
|
address.bits[2] = ipaddr_4bytes[2];
|
|
address.bits[3] = ipaddr_4bytes[3];
|
|
|
|
struct in_addr addr;
|
|
|
|
addr.s_addr = address.addr;
|
|
char* ipv4_address = inet_ntoa(addr);
|
|
if (ipv4_address == nullptr) {
|
|
return {};
|
|
}
|
|
|
|
return std::string(ipv4_address);
|
|
}
|
|
|
|
std::string ipaddr_dotdecimal_to_4bytes_string(std::string ipv4_s) {
|
|
if (ipv4_s.empty()) {
|
|
return {};
|
|
}
|
|
|
|
struct in_addr addr;
|
|
|
|
if (inet_aton(ipv4_s.c_str(), &addr) != 0) {
|
|
return {};
|
|
}
|
|
|
|
std::string ipv4_b = std::to_string(addr.s_addr);
|
|
|
|
return std::string();
|
|
}
|
|
|
|
std::wstring string_to_wstring(std::string str) {
|
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
|
return converter.from_bytes(str);
|
|
}
|
|
|
|
std::string wstring_to_string(std::wstring wstr) {
|
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
|
return converter.to_bytes(wstr);
|
|
}
|
|
|
|
std::vector<std::string> GetIpv4Addresses() {
|
|
std::vector<std::string> result;
|
|
|
|
struct ifaddrs *interface = nullptr;
|
|
char host[NI_MAXHOST];
|
|
|
|
if (getifaddrs(&interface) != 0) {
|
|
NEARBY_LOGS(ERROR) << __func__
|
|
<< ": Failed to get interfaces. Error: "
|
|
<< strerror(errno);
|
|
freeifaddrs(interface);
|
|
return {};
|
|
}
|
|
int status = 0;
|
|
for (struct ifaddrs *ifa = interface; ifa != nullptr; ifa = ifa->ifa_next) {
|
|
if (ifa->ifa_addr->sa_family == AF_INET) {
|
|
status = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST);
|
|
}
|
|
switch (status) {
|
|
case EAI_AGAIN:
|
|
NEARBY_LOGS(ERROR) << __func__
|
|
<< "Failed to get IP for interface: "
|
|
<< ifa->ifa_name
|
|
<< " : The name could not be resolved at this time. "
|
|
<< "Try again later.";
|
|
break;
|
|
case EAI_BADFLAGS:
|
|
NEARBY_LOGS(ERROR) << __func__
|
|
<< "Failed to get IP for interface: "
|
|
<< ifa->ifa_name
|
|
<< " : The flags argument has an invalid value.";
|
|
break;
|
|
case EAI_FAIL:
|
|
NEARBY_LOGS(ERROR) << __func__
|
|
<< "Failed to get IP for interface: "
|
|
<< ifa->ifa_name
|
|
<< " : A nonrecoverable error occured.";
|
|
break;
|
|
case EAI_FAMILY:
|
|
NEARBY_LOGS(ERROR) << __func__
|
|
<< "Failed to get IP for interface: "
|
|
<< ifa->ifa_name
|
|
<< " : The address family was not recognized, "
|
|
<< "or the address length was invalid for the "
|
|
<< "specified family.";
|
|
break;
|
|
case EAI_MEMORY:
|
|
NEARBY_LOGS(ERROR) << __func__
|
|
<< "Failed to get IP for interface: "
|
|
<< ifa->ifa_name
|
|
<< " : Out of memory.";
|
|
break;
|
|
case EAI_NONAME:
|
|
NEARBY_LOGS(ERROR) << __func__
|
|
<< "Failed to get IP for interface: "
|
|
<< ifa->ifa_name
|
|
<< " : The name does not resolve for the suplied arguments."
|
|
<< " NI_NAMEREQD is set and the host's name cannot be located, "
|
|
<< "or neither hostname nor service name were requsted.";
|
|
break;
|
|
case EAI_OVERFLOW:
|
|
NEARBY_LOGS(ERROR) << __func__
|
|
<< "Failed to get IP for interface: "
|
|
<< ifa->ifa_name
|
|
<< " : The bugger pointed to by `host` or `serv` was too small.";
|
|
break;
|
|
case EAI_SYSTEM:
|
|
NEARBY_LOGS(ERROR) << __func__
|
|
<< "A system error occured. Error code: "
|
|
<< errno
|
|
<< ": " << strerror(errno);
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::string> Get4BytesIpv4Addresses() {
|
|
std::vector<std::string> result;
|
|
std::vector<std::string> ipv4_addresses = GetIpv4Addresses();
|
|
for (const auto& ipv4_address : ipv4_addresses) {
|
|
// Converts IP address from x.x.x.x to 4 bytes format using utils function
|
|
result.push_back(ipaddr_dotdecimal_to_4bytes_string(ipv4_address));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
Uuid winrt_guid_to_nearby_uuid(const ::winrt::guid& guid) {
|
|
int64_t data1 = guid.Data1;
|
|
int64_t data2 = guid.Data2;
|
|
int64_t data3 = guid.Data3;
|
|
|
|
int64_t msb = ((data1 >> 24) & 0xff) << 56 | ((data1 >> 16) & 0xff) << 48 |
|
|
((data1 >> 8) & 0xff) << 40 | ((data1)&0xff) << 32 |
|
|
((data2 >> 8) & 0xff) << 24 | ((data2)&0xff) << 16 |
|
|
((data3 >> 8) & 0xff) << 8 | (data3 & 0xff);
|
|
|
|
int64_t lsb =
|
|
((int64_t)guid.Data4[0]) << 56 | ((int64_t)guid.Data4[1]) << 48 |
|
|
((int64_t)guid.Data4[2]) << 40 | ((int64_t)guid.Data4[3]) << 32 |
|
|
((int64_t)guid.Data4[4]) << 24 | ((int64_t)guid.Data4[5]) << 16 |
|
|
((int64_t)guid.Data4[6]) << 8 | (int64_t)guid.Data4[7];
|
|
|
|
return Uuid(msb, lsb);
|
|
}
|
|
*/
|
|
|
|
/*
|
|
winrt::guid nearby_uuid_to_winrt_guid(Uuid uuid) {
|
|
winrt::guid guid;
|
|
uint64_t msb = uuid.GetMostSigBits();
|
|
guid.Data1 = ((msb >> 56) & 0xff) << 24 | ((msb >> 48) & 0xff) << 16 |
|
|
((msb >> 40) & 0xff) << 8 | ((msb >> 32) & 0xff);
|
|
guid.Data2 = ((msb >> 24) & 0xff) << 8 | ((msb >> 16) & 0xff);
|
|
guid.Data3 = ((msb >> 8) & 0xff) << 8 | (msb & 0xff);
|
|
uint64_t lsb = uuid.GetLeastSigBits();
|
|
guid.Data4[0] = (lsb >> 56) & 0xff;
|
|
guid.Data4[1] = (lsb >> 48) & 0xff;
|
|
guid.Data4[2] = (lsb >> 40) & 0xff;
|
|
guid.Data4[3] = (lsb >> 32) & 0xff;
|
|
guid.Data4[4] = (lsb >> 24) & 0xff;
|
|
guid.Data4[5] = (lsb >> 16) & 0xff;
|
|
guid.Data4[6] = (lsb >> 8) & 0xff;
|
|
guid.Data4[7] = lsb & 0xff;
|
|
return guid;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
bool is_nearby_uuid_equal_to_winrt_guid(const Uuid& uuid,
|
|
const ::winrt::guid& guid) {
|
|
return uuid == winrt_guid_to_nearby_uuid(guid);
|
|
}
|
|
*/
|
|
|
|
ByteArray Sha256(absl::string_view input, size_t size) {
|
|
ByteArray hash = nearby::Crypto::Sha256(input);
|
|
return ByteArray{hash.data(), size};
|
|
}
|
|
/*
|
|
bool InspectableReader::ReadBoolean(IInspectable inspectable) {
|
|
if (inspectable == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
auto property_value =
|
|
inspectable.try_as<winrt::Windows::Foundation::IPropertyValue>();
|
|
if (property_value == nullptr) {
|
|
throw std::invalid_argument("no property value interface.");
|
|
}
|
|
if (property_value.Type() !=
|
|
winrt::Windows::Foundation::PropertyType::Boolean) {
|
|
throw std::invalid_argument("not uin16 data type.");
|
|
}
|
|
|
|
return property_value.GetBoolean();
|
|
}
|
|
|
|
uint16 InspectableReader::ReadUint16(IInspectable inspectable) {
|
|
if (inspectable == nullptr) {
|
|
return 0;
|
|
}
|
|
|
|
auto property_value =
|
|
inspectable.try_as<winrt::Windows::Foundation::IPropertyValue>();
|
|
if (property_value == nullptr) {
|
|
throw std::invalid_argument("no property value interface.");
|
|
}
|
|
if (property_value.Type() !=
|
|
winrt::Windows::Foundation::PropertyType::UInt16) {
|
|
throw std::invalid_argument("not uin16 data type.");
|
|
}
|
|
|
|
return property_value.GetUInt16();
|
|
}
|
|
|
|
uint32 InspectableReader::ReadUint32(IInspectable inspectable) {
|
|
if (inspectable == nullptr) {
|
|
return 0;
|
|
}
|
|
|
|
auto property_value =
|
|
inspectable.try_as<winrt::Windows::Foundation::IPropertyValue>();
|
|
if (property_value == nullptr) {
|
|
throw std::invalid_argument("no property value interface.");
|
|
}
|
|
if (property_value.Type() !=
|
|
winrt::Windows::Foundation::PropertyType::UInt32) {
|
|
throw std::invalid_argument("not uin32 data type.");
|
|
}
|
|
|
|
return property_value.GetUInt32();
|
|
}
|
|
|
|
std::string InspectableReader::ReadString(IInspectable inspectable) {
|
|
if (inspectable == nullptr) {
|
|
return "";
|
|
}
|
|
|
|
auto property_value =
|
|
inspectable.try_as<winrt::Windows::Foundation::IPropertyValue>();
|
|
if (property_value == nullptr) {
|
|
throw std::invalid_argument("no property value interface.");
|
|
}
|
|
if (property_value.Type() !=
|
|
winrt::Windows::Foundation::PropertyType::String) {
|
|
throw std::invalid_argument("not string data type.");
|
|
}
|
|
|
|
return wstring_to_string(property_value.GetString().c_str());
|
|
}
|
|
|
|
std::vector<std::string> InspectableReader::ReadStringArray(
|
|
IInspectable inspectable) {
|
|
std::vector<std::string> result;
|
|
if (inspectable == nullptr) {
|
|
return result;
|
|
}
|
|
|
|
auto property_value =
|
|
inspectable.try_as<winrt::Windows::Foundation::IPropertyValue>();
|
|
if (property_value == nullptr) {
|
|
throw std::invalid_argument("no property value interface.");
|
|
}
|
|
if (property_value.Type() !=
|
|
winrt::Windows::Foundation::PropertyType::StringArray) {
|
|
throw std::invalid_argument("not string array data type.");
|
|
}
|
|
|
|
winrt::com_array<winrt::hstring> strings;
|
|
property_value.GetStringArray(strings);
|
|
|
|
for (winrt::hstring str : strings) {
|
|
result.push_back(winrt::to_string(str));
|
|
}
|
|
return result;
|
|
}
|
|
*/
|
|
}
|
|
} // namespace linux
|
|
} // namespace nearby
|