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
40class C4Network2HostAddress
41{
42public:
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
62public:
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
70public:
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
99protected:
100 // Data
101 union
102 {
103 sockaddr gen;
104 sockaddr_in v4;
105 sockaddr_in6 v6;
106 };
107};
108
109class C4Network2EndpointAddress : public C4Network2HostAddress // Host and port
110{
111public:
112 static constexpr std::uint16_t IPPORT_NONE{0};
113
114public:
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
121public:
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
189enum C4Network2IOProtocol
190{
191 P_UDP, P_TCP, P_NONE = -1
192};
193
194class C4Network2Address
195{
196public:
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
229protected:
230 C4Network2EndpointAddress addr;
231 C4Network2IOProtocol protocol;
232};
233