| 1 | /* |
| 2 | * LegacyClonk |
| 3 | * |
| 4 | * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/ |
| 5 | * Copyright (c) 2013-2017, The OpenClonk Team and contributors |
| 6 | * Copyright (c) 2019, The LegacyClonk Team and contributors |
| 7 | * |
| 8 | * Distributed under the terms of the ISC license; see accompanying file |
| 9 | * "COPYING" for details. |
| 10 | * |
| 11 | * "Clonk" is a registered trademark of Matthes Bender, used with permission. |
| 12 | * See accompanying file "TRADEMARK" for details. |
| 13 | * |
| 14 | * To redistribute this file separately, substitute the full license texts |
| 15 | * for the above references. |
| 16 | */ |
| 17 | |
| 18 | #pragma once |
| 19 | |
| 20 | #include "StdBuf.h" |
| 21 | |
| 22 | #include <cstddef> |
| 23 | #include <cstdint> |
| 24 | |
| 25 | #ifdef _WIN32 |
| 26 | #include <winsock2.h> |
| 27 | #include <ws2tcpip.h> |
| 28 | #else |
| 29 | #define SOCKET int |
| 30 | #define INVALID_SOCKET (-1) |
| 31 | #include <arpa/inet.h> |
| 32 | #include <sys/socket.h> |
| 33 | #endif |
| 34 | |
| 35 | #ifndef SOCK_CLOEXEC |
| 36 | #define SOCK_CLOEXEC 0 |
| 37 | #endif |
| 38 | |
| 39 | |
| 40 | class C4Network2HostAddress |
| 41 | { |
| 42 | public: |
| 43 | enum AddressFamily |
| 44 | { |
| 45 | IPv6 = AF_INET6, |
| 46 | IPv4 = AF_INET, |
| 47 | UnknownFamily = 0 |
| 48 | }; |
| 49 | enum SpecialAddress |
| 50 | { |
| 51 | Loopback, // IPv6 localhost (::1) |
| 52 | Any, // IPv6 any-address (::) |
| 53 | AnyIPv4 // IPv4 any-address (0.0.0.0) |
| 54 | }; |
| 55 | |
| 56 | enum ToStringFlags |
| 57 | { |
| 58 | TSF_SkipZoneId = 1, |
| 59 | TSF_SkipPort = 2 |
| 60 | }; |
| 61 | |
| 62 | public: |
| 63 | C4Network2HostAddress() { Clear(); } |
| 64 | C4Network2HostAddress(const C4Network2HostAddress &other) { SetHost(other); } |
| 65 | C4Network2HostAddress(const SpecialAddress addr) { SetHost(addr); } |
| 66 | explicit C4Network2HostAddress(const std::uint32_t addr) { SetHost(addr); } |
| 67 | C4Network2HostAddress(const StdStrBuf &addr) { SetHost(host: addr); } |
| 68 | C4Network2HostAddress(const sockaddr *const addr) { SetHost(addr); } |
| 69 | |
| 70 | public: |
| 71 | AddressFamily GetFamily() const; |
| 72 | std::size_t GetAddrLen() const; |
| 73 | |
| 74 | void SetScopeId(int scopeId); |
| 75 | int GetScopeId() const; |
| 76 | |
| 77 | void Clear(); |
| 78 | void SetHost(const sockaddr *addr); |
| 79 | void SetHost(const C4Network2HostAddress &host); |
| 80 | void SetHost(SpecialAddress host); |
| 81 | void SetHost(const StdStrBuf &host, AddressFamily family = UnknownFamily); |
| 82 | void SetHost(std::uint32_t host); |
| 83 | |
| 84 | C4Network2HostAddress AsIPv6() const; // Convert an IPv4 address to an IPv6-mapped IPv4 address |
| 85 | bool IsIPv6MappedIPv4() const; |
| 86 | C4Network2HostAddress AsIPv4() const; // Try to convert an IPv6-mapped IPv4 address to an IPv4 address (returns unchanged address if not possible) |
| 87 | |
| 88 | // General categories |
| 89 | bool IsNull() const; |
| 90 | bool IsMulticast() const; |
| 91 | bool IsLoopback() const; |
| 92 | bool IsLocal() const; // IPv6 link-local address |
| 93 | bool IsPrivate() const; // IPv6 ULA or IPv4 private address range |
| 94 | |
| 95 | std::string ToString(int flags = 0) const; |
| 96 | |
| 97 | bool operator ==(const C4Network2HostAddress &rhs) const; |
| 98 | |
| 99 | protected: |
| 100 | // Data |
| 101 | union |
| 102 | { |
| 103 | sockaddr gen; |
| 104 | sockaddr_in v4; |
| 105 | sockaddr_in6 v6; |
| 106 | }; |
| 107 | }; |
| 108 | |
| 109 | class C4Network2EndpointAddress : public C4Network2HostAddress // Host and port |
| 110 | { |
| 111 | public: |
| 112 | static constexpr std::uint16_t IPPORT_NONE{0}; |
| 113 | |
| 114 | public: |
| 115 | C4Network2EndpointAddress() { Clear(); } |
| 116 | C4Network2EndpointAddress(const C4Network2EndpointAddress &other) : C4Network2HostAddress{} { SetAddress(other); } |
| 117 | C4Network2EndpointAddress(const C4Network2HostAddress &host, const std::uint16_t port = IPPORT_NONE) : C4Network2HostAddress{host} { SetPort(port); } |
| 118 | C4Network2EndpointAddress(const C4Network2HostAddress::SpecialAddress addr, const std::uint16_t port = IPPORT_NONE) : C4Network2HostAddress{addr} { SetPort(port); } |
| 119 | explicit C4Network2EndpointAddress(const StdStrBuf &addr) { SetAddress(addr); } |
| 120 | |
| 121 | public: |
| 122 | std::string ToString(int flags = 0) const; |
| 123 | |
| 124 | void Clear(); |
| 125 | |
| 126 | void SetAddress(const sockaddr *addr); |
| 127 | void SetAddress(const C4Network2EndpointAddress &other); |
| 128 | void SetAddress(C4Network2HostAddress::SpecialAddress addr, std::uint16_t port = IPPORT_NONE); |
| 129 | void SetAddress(const C4Network2HostAddress &host, std::uint16_t port = IPPORT_NONE); |
| 130 | void SetAddress(const StdStrBuf &addr, AddressFamily family = UnknownFamily); |
| 131 | void SetAddress(const std::string &addr, AddressFamily family = UnknownFamily); |
| 132 | |
| 133 | C4Network2HostAddress GetHost() const { return *this; } // HostAddress copy ctor slices off port information |
| 134 | C4Network2EndpointAddress AsIPv6() const; // Convert an IPv4 address to an IPv6-mapped IPv4 address |
| 135 | C4Network2EndpointAddress AsIPv4() const; // Try to convert an IPv6-mapped IPv4 address to an IPv4 address (returns unchanged address if not possible) |
| 136 | |
| 137 | void SetPort(std::uint16_t port); |
| 138 | void SetDefaultPort(std::uint16_t port); // Set a port only if there is none |
| 139 | std::uint16_t GetPort() const; |
| 140 | |
| 141 | bool IsNull() const; |
| 142 | bool IsNullHost() const { return C4Network2HostAddress::IsNull(); } |
| 143 | |
| 144 | // Pointer wrapper to be able to implicitly convert to sockaddr* |
| 145 | class EndpointAddressPtr; |
| 146 | const EndpointAddressPtr operator&() const; |
| 147 | EndpointAddressPtr operator&(); |
| 148 | |
| 149 | class EndpointAddressPtr |
| 150 | { |
| 151 | C4Network2EndpointAddress *const p; |
| 152 | friend EndpointAddressPtr C4Network2EndpointAddress::operator&(); |
| 153 | friend const EndpointAddressPtr C4Network2EndpointAddress::operator&() const; |
| 154 | EndpointAddressPtr(C4Network2EndpointAddress *const p) : p(p) {} |
| 155 | |
| 156 | public: |
| 157 | const C4Network2EndpointAddress &operator*() const { return *p; } |
| 158 | C4Network2EndpointAddress &operator*() { return *p; } |
| 159 | |
| 160 | const C4Network2EndpointAddress &operator->() const { return *p; } |
| 161 | C4Network2EndpointAddress &operator->() { return *p; } |
| 162 | |
| 163 | operator const C4Network2EndpointAddress *() const { return p; } |
| 164 | operator C4Network2EndpointAddress *() { return p; } |
| 165 | |
| 166 | operator const sockaddr *() const { return &p->gen; } |
| 167 | operator sockaddr *() { return &p->gen; } |
| 168 | |
| 169 | operator const sockaddr_in *() const { return &p->v4; } |
| 170 | operator sockaddr_in *() { return &p->v4; } |
| 171 | |
| 172 | operator const sockaddr_in6 *() const { return &p->v6; } |
| 173 | operator sockaddr_in6 *() { return &p->v6; } |
| 174 | }; |
| 175 | |
| 176 | bool operator==(const C4Network2EndpointAddress &rhs) const; |
| 177 | |
| 178 | // Conversions |
| 179 | operator sockaddr() const { return gen; } |
| 180 | operator sockaddr_in() const { assert(gen.sa_family == AF_INET); return v4; } |
| 181 | operator sockaddr_in6() const { assert(gen.sa_family == AF_INET6); return v6; } |
| 182 | |
| 183 | // StdCompiler |
| 184 | void CompileFunc(StdCompiler *comp); |
| 185 | |
| 186 | friend class EndpointAddressPtr; |
| 187 | }; |
| 188 | |
| 189 | enum C4Network2IOProtocol |
| 190 | { |
| 191 | P_UDP, P_TCP, P_NONE = -1 |
| 192 | }; |
| 193 | |
| 194 | class C4Network2Address |
| 195 | { |
| 196 | public: |
| 197 | C4Network2Address() |
| 198 | : protocol{P_NONE} {} |
| 199 | |
| 200 | C4Network2Address(const C4Network2EndpointAddress addr, const C4Network2IOProtocol protocol) |
| 201 | : addr{addr.AsIPv4()}, protocol{protocol} {} |
| 202 | |
| 203 | C4Network2Address(const C4Network2Address &addr) |
| 204 | : addr{addr.GetAddr()}, protocol{addr.GetProtocol()} {} |
| 205 | |
| 206 | void operator=(const C4Network2Address &addr) |
| 207 | { |
| 208 | SetAddr(addr.GetAddr()); |
| 209 | SetProtocol(addr.GetProtocol()); |
| 210 | } |
| 211 | |
| 212 | bool operator==(const C4Network2Address &addr) const; |
| 213 | |
| 214 | const C4Network2EndpointAddress &GetAddr() const { return addr; } |
| 215 | C4Network2EndpointAddress &GetAddr() { return addr; } |
| 216 | bool isIPNull() const { return addr.IsNull(); } |
| 217 | std::uint16_t GetPort() const { return addr.GetPort(); } |
| 218 | C4Network2IOProtocol GetProtocol() const { return protocol; } |
| 219 | |
| 220 | std::string ToString() const; |
| 221 | |
| 222 | void SetAddr(const C4Network2EndpointAddress naddr) { addr = naddr.AsIPv4(); } |
| 223 | void SetIP(const C4Network2EndpointAddress ip) { addr.SetAddress(ip.AsIPv4()); } |
| 224 | void SetPort(const std::uint16_t port) { addr.SetPort(port); } |
| 225 | void SetProtocol(const C4Network2IOProtocol protocol) { this->protocol = protocol; } |
| 226 | |
| 227 | void CompileFunc(StdCompiler *comp); |
| 228 | |
| 229 | protected: |
| 230 | C4Network2EndpointAddress addr; |
| 231 | C4Network2IOProtocol protocol; |
| 232 | }; |
| 233 | |