Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/core/StarHostAddress.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/core/StarHostAddress.cpp')
-rw-r--r--source/core/StarHostAddress.cpp281
1 files changed, 281 insertions, 0 deletions
diff --git a/source/core/StarHostAddress.cpp b/source/core/StarHostAddress.cpp
new file mode 100644
index 0000000..f65f179
--- /dev/null
+++ b/source/core/StarHostAddress.cpp
@@ -0,0 +1,281 @@
+#include "StarHostAddress.hpp"
+#include "StarLexicalCast.hpp"
+#include "StarNetImpl.hpp"
+
+namespace Star {
+
+HostAddress HostAddress::localhost(NetworkMode mode) {
+ if (mode == NetworkMode::IPv4) {
+ uint8_t addr[4] = {127, 0, 0, 1};
+ return HostAddress(mode, addr);
+ } else if (mode == NetworkMode::IPv6) {
+ uint8_t addr[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+ return HostAddress(mode, addr);
+ }
+
+ return HostAddress();
+}
+
+Either<String, HostAddress> HostAddress::lookup(String const& address) {
+ try {
+ HostAddress ha;
+ ha.set(address);
+ return makeRight(move(ha));
+ } catch (NetworkException const& e) {
+ return makeLeft(String(e.what()));
+ }
+}
+
+HostAddress::HostAddress(NetworkMode mode, uint8_t* address) {
+ set(mode, address);
+}
+
+HostAddress::HostAddress(String const& address) {
+ auto a = lookup(address);
+ if (a.isLeft())
+ throw NetworkException(a.left().takeUtf8());
+ else
+ *this = move(a.right());
+}
+
+NetworkMode HostAddress::mode() const {
+ return m_mode;
+}
+
+uint8_t const* HostAddress::bytes() const {
+ return m_address;
+}
+
+uint8_t HostAddress::octet(size_t i) const {
+ return m_address[i];
+}
+
+bool HostAddress::isLocalHost() const {
+ if (m_mode == NetworkMode::IPv4) {
+ return (m_address[0] == 127 && m_address[1] == 0 && m_address[2] == 0 && m_address[3] == 1);
+
+ } else {
+ for (size_t i = 0; i < 15; ++i) {
+ if (m_address[i] != 0)
+ return false;
+ }
+
+ return m_address[15] == 1;
+ }
+}
+
+bool HostAddress::isZero() const {
+ if (mode() == NetworkMode::IPv4)
+ return m_address[0] == 0 && m_address[1] == 0 && m_address[2] == 0 && m_address[3] == 0;
+
+ if (mode() == NetworkMode::IPv6) {
+ for (size_t i = 0; i < 16; i++) {
+ if (m_address[i] != 0)
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+size_t HostAddress::size() const {
+ switch (m_mode) {
+ case NetworkMode::IPv4:
+ return 4;
+ case NetworkMode::IPv6:
+ return 16;
+ default:
+ return 0;
+ }
+}
+
+bool HostAddress::operator==(HostAddress const& a) const {
+ if (m_mode != a.m_mode)
+ return false;
+
+ size_t len = a.size();
+ for (size_t i = 0; i < len; i++) {
+ if (m_address[i] != a.m_address[i])
+ return false;
+ }
+
+ return true;
+}
+
+void HostAddress::set(String const& address) {
+ if (address.empty())
+ return;
+
+ if (address.compare("*") == 0 || address.compare("0.0.0.0") == 0) {
+ uint8_t inaddr_any[4];
+ memset(inaddr_any, 0, sizeof(inaddr_any));
+ set(NetworkMode::IPv4, inaddr_any);
+ } else if (address.compare("::") == 0) {
+ // NOTE: This will likely bind to both IPv6 and IPv4, but it does depending
+ // on the OS settings
+ uint8_t inaddr_any[16];
+ memset(inaddr_any, 0, sizeof(inaddr_any));
+ set(NetworkMode::IPv6, inaddr_any);
+ } else {
+ struct addrinfo* result = NULL;
+ struct addrinfo* ptr = NULL;
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ // Eliminate duplicates being returned one for each socket type.
+ // As we're not using the return socket type or protocol this doesn't effect
+ // us.
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ // Request only usable addresses e.g. IPv6 only if IPv6 is available
+ hints.ai_flags = AI_ADDRCONFIG;
+
+ if (::getaddrinfo(address.utf8Ptr(), NULL, &hints, &result) != 0)
+ throw NetworkException(strf("Failed to determine address for '%s' (%s)", address, netErrorString()));
+
+ for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
+ NetworkMode mode;
+ switch (ptr->ai_family) {
+ case AF_INET:
+ mode = NetworkMode::IPv4;
+ break;
+ case AF_INET6:
+ mode = NetworkMode::IPv6;
+ break;
+ default:
+ continue;
+ }
+ if (mode == NetworkMode::IPv4) {
+ struct sockaddr_in* info = (struct sockaddr_in*)ptr->ai_addr;
+ set(mode, (uint8_t*)(&info->sin_addr));
+ } else {
+ struct sockaddr_in6* info = (struct sockaddr_in6*)ptr->ai_addr;
+ set(mode, (uint8_t*)(&info->sin6_addr));
+ }
+ break;
+ }
+ freeaddrinfo(result);
+ }
+}
+
+void HostAddress::set(NetworkMode mode, uint8_t const* addr) {
+ m_mode = mode;
+ if (addr)
+ memcpy(m_address, addr, size());
+ else
+ memset(m_address, 0, 16);
+}
+
+std::ostream& operator<<(std::ostream& os, HostAddress const& address) {
+ switch (address.mode()) {
+ case NetworkMode::IPv4:
+ format(os, "%d.%d.%d.%d", address.octet(0), address.octet(1), address.octet(2), address.octet(3));
+ break;
+
+ case NetworkMode::IPv6:
+ format(os,
+ "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
+ address.octet(0),
+ address.octet(1),
+ address.octet(2),
+ address.octet(3),
+ address.octet(4),
+ address.octet(5),
+ address.octet(6),
+ address.octet(7),
+ address.octet(8),
+ address.octet(9),
+ address.octet(10),
+ address.octet(11),
+ address.octet(12),
+ address.octet(13),
+ address.octet(14),
+ address.octet(15));
+ break;
+
+ default:
+ throw NetworkException(strf("Unknown address mode (%d)", (int)address.mode()));
+ }
+ return os;
+}
+
+size_t hash<HostAddress>::operator()(HostAddress const& address) const {
+ PLHasher hash;
+ for (size_t i = 0; i < address.size(); ++i)
+ hash.put(address.octet(i));
+ return hash.hash();
+}
+
+Either<String, HostAddressWithPort> HostAddressWithPort::lookup(String const& address, uint16_t port) {
+ auto hostAddress = HostAddress::lookup(address);
+ if (hostAddress.isLeft())
+ return makeLeft(move(hostAddress.left()));
+ else
+ return makeRight(HostAddressWithPort(move(hostAddress.right()), port));
+}
+
+Either<String, HostAddressWithPort> HostAddressWithPort::lookupWithPort(String const& address) {
+ String host = address;
+ String port = host.rextract(":");
+ if (host.beginsWith("[") && host.endsWith("]"))
+ host = host.substr(1, host.size() - 2);
+
+ auto portNum = maybeLexicalCast<uint16_t>(port);
+ if (!portNum)
+ return makeLeft(strf("Could not parse port portion of HostAddressWithPort '%s'", port));
+
+ auto hostAddress = HostAddress::lookup(host);
+ if (hostAddress.isLeft())
+ return makeLeft(move(hostAddress.left()));
+
+ return makeRight(HostAddressWithPort(move(hostAddress.right()), *portNum));
+}
+
+HostAddressWithPort::HostAddressWithPort() : m_port(0) {}
+
+HostAddressWithPort::HostAddressWithPort(HostAddress const& address, uint16_t port)
+ : m_address(address), m_port(port) {}
+
+HostAddressWithPort::HostAddressWithPort(NetworkMode mode, uint8_t* address, uint16_t port) {
+ m_address = HostAddress(mode, address);
+ m_port = port;
+}
+
+HostAddressWithPort::HostAddressWithPort(String const& address, uint16_t port) {
+ auto a = lookup(address, port);
+ if (a.isLeft())
+ throw NetworkException(a.left().takeUtf8());
+ *this = move(a.right());
+}
+
+HostAddressWithPort::HostAddressWithPort(String const& address) {
+ auto a = lookupWithPort(address);
+ if (a.isLeft())
+ throw NetworkException(a.left().takeUtf8());
+ *this = move(a.right());
+}
+
+HostAddress HostAddressWithPort::address() const {
+ return m_address;
+}
+
+uint16_t HostAddressWithPort::port() const {
+ return m_port;
+}
+
+bool HostAddressWithPort::operator==(HostAddressWithPort const& rhs) const {
+ return tie(m_address, m_port) == tie(rhs.m_address, rhs.m_port);
+}
+
+std::ostream& operator<<(std::ostream& os, HostAddressWithPort const& addressWithPort) {
+ os << addressWithPort.address() << ":" << addressWithPort.port();
+ return os;
+}
+
+size_t hash<HostAddressWithPort>::operator()(HostAddressWithPort const& addressWithPort) const {
+ return hashOf(addressWithPort.address(), addressWithPort.port());
+}
+
+}