mirror of
https://github.com/thinkonmay/sunshine-sdk.git
synced 2025-12-27 23:48:53 +00:00
210 lines
5.1 KiB
C++
210 lines
5.1 KiB
C++
/**
|
|
* @file src/network.cpp
|
|
* @brief todo
|
|
*/
|
|
#include "network.h"
|
|
#include "utility.h"
|
|
#include <algorithm>
|
|
|
|
using namespace std::literals;
|
|
namespace net {
|
|
// In the format "xxx.xxx.xxx.xxx/x"
|
|
std::pair<std::uint32_t, std::uint32_t>
|
|
ip_block(const std::string_view &ip);
|
|
|
|
std::vector<std::pair<std::uint32_t, std::uint32_t>> pc_ips {
|
|
ip_block("127.0.0.1/32"sv)
|
|
};
|
|
std::vector<std::tuple<std::uint32_t, std::uint32_t>> lan_ips {
|
|
ip_block("192.168.0.0/16"sv),
|
|
ip_block("172.16.0.0/12"sv),
|
|
ip_block("10.0.0.0/8"sv),
|
|
ip_block("100.64.0.0/10"sv),
|
|
ip_block("169.254.0.0/16"sv)
|
|
};
|
|
|
|
std::uint32_t
|
|
ip(const std::string_view &ip_str) {
|
|
auto begin = std::begin(ip_str);
|
|
auto end = std::end(ip_str);
|
|
auto temp_end = std::find(begin, end, '.');
|
|
|
|
std::uint32_t ip = 0;
|
|
auto shift = 24;
|
|
while (temp_end != end) {
|
|
ip += (util::from_chars(begin, temp_end) << shift);
|
|
shift -= 8;
|
|
|
|
begin = temp_end + 1;
|
|
temp_end = std::find(begin, end, '.');
|
|
}
|
|
|
|
ip += util::from_chars(begin, end);
|
|
|
|
return ip;
|
|
}
|
|
|
|
// In the format "xxx.xxx.xxx.xxx/x"
|
|
std::pair<std::uint32_t, std::uint32_t>
|
|
ip_block(const std::string_view &ip_str) {
|
|
auto begin = std::begin(ip_str);
|
|
auto end = std::find(begin, std::end(ip_str), '/');
|
|
|
|
auto addr = ip({ begin, (std::size_t)(end - begin) });
|
|
|
|
auto bits = 32 - util::from_chars(end + 1, std::end(ip_str));
|
|
|
|
return { addr, addr + ((1 << bits) - 1) };
|
|
}
|
|
|
|
net_e
|
|
from_enum_string(const std::string_view &view) {
|
|
if (view == "wan") {
|
|
return WAN;
|
|
}
|
|
if (view == "lan") {
|
|
return LAN;
|
|
}
|
|
|
|
return PC;
|
|
}
|
|
net_e
|
|
from_address(const std::string_view &view) {
|
|
auto addr = ip(view);
|
|
|
|
for (auto [ip_low, ip_high] : pc_ips) {
|
|
if (addr >= ip_low && addr <= ip_high) {
|
|
return PC;
|
|
}
|
|
}
|
|
|
|
for (auto [ip_low, ip_high] : lan_ips) {
|
|
if (addr >= ip_low && addr <= ip_high) {
|
|
return LAN;
|
|
}
|
|
}
|
|
|
|
return WAN;
|
|
}
|
|
|
|
std::string_view
|
|
to_enum_string(net_e net) {
|
|
switch (net) {
|
|
case PC:
|
|
return "pc"sv;
|
|
case LAN:
|
|
return "lan"sv;
|
|
case WAN:
|
|
return "wan"sv;
|
|
}
|
|
|
|
// avoid warning
|
|
return "wan"sv;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the `af_e` enum value for the `address_family` config option value.
|
|
* @param view The config option value.
|
|
* @return The `af_e` enum value.
|
|
*/
|
|
af_e
|
|
af_from_enum_string(const std::string_view &view) {
|
|
if (view == "ipv4") {
|
|
return IPV4;
|
|
}
|
|
if (view == "both") {
|
|
return BOTH;
|
|
}
|
|
|
|
// avoid warning
|
|
return BOTH;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the wildcard binding address for a given address family.
|
|
* @param af Address family.
|
|
* @return Normalized address.
|
|
*/
|
|
std::string_view
|
|
af_to_any_address_string(af_e af) {
|
|
switch (af) {
|
|
case IPV4:
|
|
return "0.0.0.0"sv;
|
|
case BOTH:
|
|
return "::"sv;
|
|
}
|
|
|
|
// avoid warning
|
|
return "::"sv;
|
|
}
|
|
|
|
/**
|
|
* @brief Converts an address to a normalized form.
|
|
* @details Normalization converts IPv4-mapped IPv6 addresses into IPv4 addresses.
|
|
* @param address The address to normalize.
|
|
* @return Normalized address.
|
|
*/
|
|
boost::asio::ip::address
|
|
normalize_address(boost::asio::ip::address address) {
|
|
// Convert IPv6-mapped IPv4 addresses into regular IPv4 addresses
|
|
if (address.is_v6()) {
|
|
auto v6 = address.to_v6();
|
|
if (v6.is_v4_mapped()) {
|
|
return boost::asio::ip::make_address_v4(boost::asio::ip::v4_mapped, v6);
|
|
}
|
|
}
|
|
|
|
return address;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the given address in normalized string form.
|
|
* @details Normalization converts IPv4-mapped IPv6 addresses into IPv4 addresses.
|
|
* @param address The address to normalize.
|
|
* @return Normalized address in string form.
|
|
*/
|
|
std::string
|
|
addr_to_normalized_string(boost::asio::ip::address address) {
|
|
return normalize_address(address).to_string();
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the given address in a normalized form for in the host portion of a URL.
|
|
* @details Normalization converts IPv4-mapped IPv6 addresses into IPv4 addresses.
|
|
* @param address The address to normalize and escape.
|
|
* @return Normalized address in URL-escaped string.
|
|
*/
|
|
std::string
|
|
addr_to_url_escaped_string(boost::asio::ip::address address) {
|
|
address = normalize_address(address);
|
|
if (address.is_v6()) {
|
|
return "["s + address.to_string() + ']';
|
|
}
|
|
else {
|
|
return address.to_string();
|
|
}
|
|
}
|
|
|
|
host_t
|
|
host_create(af_e af, ENetAddress &addr, std::size_t peers, std::uint16_t port) {
|
|
auto any_addr = net::af_to_any_address_string(af);
|
|
enet_address_set_host(&addr, any_addr.data());
|
|
enet_address_set_port(&addr, port);
|
|
|
|
return host_t { enet_host_create(af == IPV4 ? AF_INET : AF_INET6, &addr, peers, 0, 0, 0) };
|
|
}
|
|
|
|
void
|
|
free_host(ENetHost *host) {
|
|
std::for_each(host->peers, host->peers + host->peerCount, [](ENetPeer &peer_ref) {
|
|
ENetPeer *peer = &peer_ref;
|
|
|
|
if (peer) {
|
|
enet_peer_disconnect_now(peer, 0);
|
|
}
|
|
});
|
|
|
|
enet_host_destroy(host);
|
|
}
|
|
} // namespace net
|