Branch data Line data Source code
1 : : /*
2 : : ** Copyright (C) 2022 CERN
3 : : **
4 : : ** This software is provided 'as-is', without any express or implied
5 : : ** warranty. In no event will the authors be held liable for any damages
6 : : ** arising from the use of this software.
7 : : **
8 : : ** Permission is granted to anyone to use this software for any purpose,
9 : : ** including commercial applications, and to alter it and redistribute it
10 : : ** freely, subject to the following restrictions:
11 : : **
12 : : ** 1. The origin of this software must not be misrepresented; you must not
13 : : ** claim that you wrote the original software. If you use this software
14 : : ** in a product, an acknowledgment in the product documentation would be
15 : : ** appreciated but is not required.
16 : : ** 2. Altered source versions must be plainly marked as such, and must not be
17 : : ** misrepresented as being the original software.
18 : : ** 3. This notice may not be removed or altered from any source distribution.
19 : : **
20 : : ** Created on: 2022-11-29T09:50:18
21 : : ** Author: Sylvain Fargier <sylvain.fargier@cern.ch>
22 : : */
23 : :
24 : : #include "Addr.hpp"
25 : :
26 : : #include <algorithm>
27 : : #include <chrono>
28 : : #include <cstring>
29 : : #include <thread>
30 : : #include <vector>
31 : :
32 : : #include <arpa/inet.h>
33 : : #include <logger/Logger.hpp>
34 : : #include <netinet/in.h>
35 : : #include <poll.h>
36 : : #include <sys/socket.h>
37 : : #include <unistd.h>
38 : :
39 : : #include "../Exception.hpp"
40 : :
41 : : namespace ccut {
42 : : namespace net {
43 : :
44 : 30 : static struct sockaddr *make4(const std::string &str, uint16_t port)
45 : : {
46 : 30 : sockaddr_in *ret = new sockaddr_in;
47 : 30 : memset(ret, 0, sizeof(sockaddr_in));
48 : 30 : if (inet_pton(AF_INET, str.data(), &ret->sin_addr) <= 0)
49 : : {
50 : 1 : logger::error("ccut::net") << "invalid ipv4 addr: " << str;
51 : 1 : delete ret;
52 : 1 : return nullptr;
53 : : }
54 : 29 : ret->sin_family = AF_INET;
55 : 29 : ret->sin_port = htons(port);
56 : 29 : return reinterpret_cast<sockaddr *>(ret);
57 : : }
58 : :
59 : 23 : static struct sockaddr *make6(const std::string &str, uint16_t port)
60 : : {
61 : 23 : sockaddr_in6 *ret = new sockaddr_in6;
62 : 23 : memset(ret, 0, sizeof(sockaddr_in6));
63 : 23 : if (inet_pton(AF_INET6, str.data(), &ret->sin6_addr) <= 0)
64 : : {
65 : 1 : logger::error("ccut::net") << "invalid ipv6 addr: " << str;
66 : 1 : delete ret;
67 : 1 : return nullptr;
68 : : }
69 : 22 : ret->sin6_family = AF_INET6;
70 : 22 : ret->sin6_port = htons(port);
71 : 22 : return reinterpret_cast<sockaddr *>(ret);
72 : : }
73 : :
74 : 41 : Addr::Addr(const std::string &addr, uint16_t port)
75 : : {
76 : 41 : if (addr.find('.') != std::string::npos)
77 : 22 : m_addr.reset(make4(addr, port));
78 : : else
79 : 19 : m_addr.reset(make6(addr, port));
80 : 41 : }
81 : :
82 : 12 : Addr::Addr(int inet, const std::string &addr, uint16_t port)
83 : : {
84 : 12 : if (inet == AF_INET6)
85 : 4 : m_addr.reset(make6(addr, port));
86 : : else
87 : 8 : m_addr.reset(make4(addr, port));
88 : 12 : }
89 : :
90 : 21 : bool Addr::operator==(const Addr &other) const
91 : : {
92 : 21 : if (!m_addr)
93 : 2 : return !other.m_addr;
94 : 19 : else if (!other.m_addr)
95 : 1 : return false;
96 : 18 : return (m_addr->sa_family == other.m_addr->sa_family) &&
97 : 36 : (port() == other.port()) && (host() == other.host());
98 : : }
99 : :
100 : 38 : void Addr::detach()
101 : : {
102 : 38 : if (!m_addr || m_addr.use_count() <= 1)
103 : 30 : return;
104 : 8 : switch (m_addr->sa_family)
105 : : {
106 : 5 : case AF_INET:
107 : : {
108 : 5 : struct sockaddr_in *sock = new sockaddr_in;
109 : 5 : *sock = reinterpret_cast<const sockaddr_in &>(*m_addr);
110 : 5 : m_addr.reset(reinterpret_cast<sockaddr *>(sock));
111 : 5 : break;
112 : : }
113 : 3 : case AF_INET6:
114 : : {
115 : 3 : struct sockaddr_in6 *sock = new sockaddr_in6;
116 : 3 : *sock = reinterpret_cast<const sockaddr_in6 &>(*m_addr);
117 : 3 : m_addr.reset(reinterpret_cast<sockaddr *>(sock));
118 : 3 : break;
119 : : }
120 : 0 : default: break;
121 : : }
122 : : }
123 : :
124 : 47 : uint16_t Addr::port() const
125 : : {
126 : 47 : if (!m_addr)
127 : 1 : return 0;
128 : 46 : switch (m_addr->sa_family)
129 : : {
130 : 24 : case AF_INET:
131 : 24 : return ntohs(reinterpret_cast<const sockaddr_in &>(*m_addr).sin_port);
132 : 22 : case AF_INET6:
133 : 22 : return ntohs(reinterpret_cast<const sockaddr_in6 &>(*m_addr).sin6_port);
134 : 0 : default: return 0;
135 : : }
136 : : }
137 : :
138 : 47 : std::string Addr::host() const
139 : : {
140 : 47 : if (!m_addr)
141 : 1 : return std::string();
142 : 46 : switch (m_addr->sa_family)
143 : : {
144 : 22 : case AF_INET:
145 : : {
146 : 22 : std::vector<char> buf;
147 : 22 : buf.reserve(INET_ADDRSTRLEN);
148 : 22 : const char *ret = inet_ntop(
149 : : AF_INET,
150 : 22 : &reinterpret_cast<const sockaddr_in *>(m_addr.get())->sin_addr,
151 : 22 : buf.data(), buf.capacity());
152 : 22 : return ret ? std::string(ret) : std::string();
153 : 22 : }
154 : 24 : case AF_INET6:
155 : : {
156 : 24 : std::vector<char> buf;
157 : 24 : buf.reserve(INET6_ADDRSTRLEN);
158 : 24 : const char *ret = inet_ntop(
159 : : AF_INET6,
160 : 24 : &reinterpret_cast<const sockaddr_in6 *>(m_addr.get())->sin6_addr,
161 : 24 : buf.data(), buf.capacity());
162 : 24 : return ret ? std::string(ret) : std::string();
163 : 24 : }
164 : 0 : default: return std::string();
165 : : }
166 : : }
167 : :
168 : 34 : size_t Addr::size() const
169 : : {
170 : 34 : if (!m_addr)
171 : 1 : return 0;
172 : 33 : switch (m_addr->sa_family)
173 : : {
174 : 22 : case AF_INET: return sizeof(sockaddr_in);
175 : 11 : case AF_INET6: return sizeof(sockaddr_in6);
176 : 0 : default: return 0;
177 : : }
178 : : }
179 : :
180 : 54 : bool Addr::isV6() const
181 : : {
182 : 54 : if (!m_addr)
183 : 0 : return false;
184 : 54 : switch (m_addr->sa_family)
185 : : {
186 : 15 : case AF_INET: return false;
187 : 39 : case AF_INET6: return true;
188 : 0 : default: return false;
189 : : }
190 : : }
191 : :
192 : 5 : bool Addr::toBuffer(buffer_view_t<cow_ptr<buffer_t>> &buffer) const
193 : : {
194 : 5 : if (!m_addr)
195 : 1 : return false;
196 : :
197 : 4 : switch (m_addr->sa_family)
198 : : {
199 : 2 : case AF_INET:
200 : 2 : if (buffer.size() < 4)
201 : 1 : return false;
202 : 2 : memcpy(buffer.data(),
203 : 1 : &reinterpret_cast<const sockaddr_in *>(m_addr.get())->sin_addr,
204 : : 4);
205 : 1 : return true;
206 : 2 : case AF_INET6:
207 : 2 : if (buffer.size() < 16)
208 : 1 : return false;
209 : 2 : memcpy(buffer.data(),
210 : 1 : &reinterpret_cast<const sockaddr_in6 *>(m_addr.get())->sin6_addr,
211 : : 16);
212 : 1 : return true;
213 : 0 : default: return false;
214 : : }
215 : : }
216 : :
217 : 3 : cow_ptr<buffer_t> Addr::toBuffer() const
218 : : {
219 : 3 : if (!m_addr)
220 : 1 : return cow_ptr<buffer_t>();
221 : :
222 : 2 : switch (m_addr->sa_family)
223 : : {
224 : 1 : case AF_INET:
225 : : {
226 : 1 : buffer_view_t<cow_ptr<buffer_t>> ret{make_cow<buffer_t>(4, 0)};
227 : 1 : if (toBuffer(ret))
228 : 1 : return ret.buffer();
229 : 1 : }
230 : : case AF_INET6:
231 : : {
232 : 1 : buffer_view_t<cow_ptr<buffer_t>> ret{make_cow<buffer_t>(16, 0)};
233 : 1 : if (toBuffer(ret))
234 : 1 : return ret.buffer();
235 : 1 : }
236 : : }
237 : 0 : return cow_ptr<buffer_t>();
238 : : }
239 : :
240 : 18 : Addr::Addr(const buffer_view_t<cow_ptr<buffer_t>> &buffer)
241 : : {
242 : 18 : *this = buffer;
243 : 18 : }
244 : :
245 : 23 : Addr &Addr::operator=(const buffer_view_t<cow_ptr<buffer_t>> &buffer)
246 : : {
247 : 23 : if (buffer.size() >= 16)
248 : : {
249 : 10 : detach();
250 : : sockaddr_in6 *ret;
251 : 10 : if (!m_addr || m_addr->sa_family != AF_INET6)
252 : : {
253 : 9 : ret = new sockaddr_in6;
254 : 9 : m_addr.reset(reinterpret_cast<sockaddr *>(ret));
255 : : }
256 : : else /* already IPv6, let's optimize */
257 : 1 : ret = reinterpret_cast<sockaddr_in6 *>(m_addr.get());
258 : :
259 : 10 : memset(ret, 0, sizeof(sockaddr_in6));
260 : 10 : memcpy(&ret->sin6_addr, buffer.data(), 16);
261 : 10 : ret->sin6_family = AF_INET6;
262 : 10 : ret->sin6_port = 0;
263 : : }
264 : 13 : else if (buffer.size() >= 4)
265 : : {
266 : 10 : detach();
267 : : sockaddr_in *ret;
268 : 10 : if (!m_addr || m_addr->sa_family != AF_INET)
269 : : {
270 : 9 : ret = new sockaddr_in;
271 : 9 : m_addr.reset(reinterpret_cast<sockaddr *>(ret));
272 : : }
273 : : else
274 : 1 : ret = reinterpret_cast<sockaddr_in *>(m_addr.get());
275 : :
276 : 10 : memset(ret, 0, sizeof(sockaddr_in));
277 : 10 : memcpy(&ret->sin_addr.s_addr, buffer.data(), 4);
278 : 10 : ret->sin_family = AF_INET;
279 : 10 : ret->sin_port = 0;
280 : : }
281 : : else
282 : 3 : *this = Addr();
283 : 23 : return *this;
284 : : }
285 : :
286 : 16 : const logger::Logger &operator<<(const logger::Logger &logger,
287 : : const ccut::net::Addr &addr)
288 : : {
289 : 16 : if (logger.isEnabled())
290 : : {
291 : 4 : if (!addr.isValid())
292 : 1 : logger << "invalid";
293 : 3 : else if (addr.addr()->sa_family == AF_INET6)
294 : : // IPv6 URI notation as per RFC3986
295 : 2 : logger << "[" << addr.host() << "]:" << addr.port();
296 : : else
297 : 1 : logger << addr.host() << ":" << addr.port();
298 : : }
299 : 16 : return logger;
300 : : }
301 : :
302 : : } // namespace net
303 : : } // namespace ccut
|