LibSWOC++ 1.5.14
Solid Wall of C++
Loading...
Searching...
No Matches
bw_ip_format.cc
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright Apache Software Foundation 2019
7
8#include "swoc/swoc_ip.h"
9#include "swoc/bwf_ip.h"
10
11using namespace swoc::literals;
12
13namespace swoc { inline namespace SWOC_VERSION_NS {
14using bwf::Spec;
15
16BufferWriter &
17bwformat(BufferWriter &w, Spec const &spec, in6_addr const &addr) {
18 using QUAD = uint16_t const;
19 Spec local_spec{spec}; // Format for address elements.
20 uint8_t const *ptr = addr.s6_addr;
21 uint8_t const *limit = ptr + sizeof(addr.s6_addr);
22 QUAD *lower = nullptr; // the best zero range
23 QUAD *upper = nullptr;
24 bool align_p = false;
25
26 if (spec._ext.size()) {
27 if (spec._ext.front() == '=') {
28 align_p = true;
29 local_spec._fill = '0';
30 } else if (spec._ext.size() > 1 && spec._ext[1] == '=') {
31 align_p = true;
32 local_spec._fill = spec._ext[0];
33 }
34 }
35
36 if (align_p) {
37 local_spec._min = 4;
38 local_spec._align = Spec::Align::RIGHT;
39 } else {
40 local_spec._min = 0;
41 // do 0 compression if there's no internal fill.
42 for (QUAD *spot = reinterpret_cast<QUAD *>(ptr), *last = reinterpret_cast<QUAD *>(limit), *current = nullptr; spot < last;
43 ++spot) {
44 if (0 == *spot) {
45 if (current) {
46 // If there's no best, or this is better, remember it.
47 if (!lower || (upper - lower < spot - current)) {
48 lower = current;
49 upper = spot;
50 }
51 } else {
52 current = spot;
53 }
54 } else {
55 current = nullptr;
56 }
57 }
58 }
59
60 if (!local_spec.has_numeric_type()) {
61 local_spec._type = 'x';
62 }
63
64 for (; ptr < limit; ptr += 2) {
65 if (reinterpret_cast<uint8_t const *>(lower) <= ptr && ptr <= reinterpret_cast<uint8_t const *>(upper)) {
66 if (ptr == addr.s6_addr) {
67 w.write(':'); // only if this is the first quad.
68 }
69 if (ptr == reinterpret_cast<uint8_t const *>(upper)) {
70 w.write(':');
71 }
72 } else {
73 uint16_t f = (ptr[0] << 8) + ptr[1];
74 bwformat(w, local_spec, f);
75 if (ptr != limit - 2) {
76 w.write(':');
77 }
78 }
79 }
80 return w;
81}
82
83BufferWriter &
84bwformat(BufferWriter &w, Spec const &spec, sockaddr const *addr) {
85 Spec local_spec{spec}; // Format for address elements and port.
86 bool port_p{true};
87 bool addr_p{true};
88 bool family_p{false};
89 bool local_numeric_fill_p{false};
90 char local_numeric_fill_char{'0'};
91
92 if (spec._type == 'p' || spec._type == 'P') {
93 bwformat(w, spec, static_cast<void const *>(addr));
94 return w;
95 }
96
97 if (spec._ext.size()) {
98 if (spec._ext.front() == '=') {
99 local_numeric_fill_p = true;
100 local_spec._ext.remove_prefix(1);
101 } else if (spec._ext.size() > 1 && spec._ext[1] == '=') {
102 local_numeric_fill_p = true;
103 local_numeric_fill_char = spec._ext.front();
104 local_spec._ext.remove_prefix(2);
105 }
106 }
107 if (local_spec._ext.size()) {
108 addr_p = port_p = false;
109 for (char c : local_spec._ext) {
110 switch (c) {
111 case 'a':
112 case 'A':
113 addr_p = true;
114 break;
115 case 'p':
116 case 'P':
117 port_p = true;
118 break;
119 case 'f':
120 case 'F':
121 family_p = true;
122 break;
123 }
124 }
125 }
126
127 if (addr_p) {
128 bool bracket_p = false;
129 switch (addr->sa_family) {
130 case AF_INET:
131 bwformat(w, spec, IP4Addr{IP4Addr::reorder(reinterpret_cast<sockaddr_in const *>(addr)->sin_addr.s_addr)});
132 break;
133 case AF_INET6:
134 if (port_p) {
135 w.write('[');
136 bracket_p = true; // take a note - put in the trailing bracket.
137 }
138 bwformat(w, spec, reinterpret_cast<sockaddr_in6 const *>(addr)->sin6_addr);
139 break;
140 default:
141 w.print("*Invalid IP family [{}]*", addr->sa_family);
142 break;
143 }
144 if (bracket_p) {
145 w.write(']');
146 }
147 if (port_p) {
148 w.write(':');
149 }
150 }
151 if (port_p) {
152 if (local_numeric_fill_p) {
153 local_spec._min = 5;
154 local_spec._fill = local_numeric_fill_char;
155 local_spec._align = Spec::Align::RIGHT;
156 } else {
157 local_spec._min = 0;
158 }
159 bwformat(w, local_spec, static_cast<uintmax_t>(IPEndpoint::host_order_port(addr)));
160 }
161 if (family_p) {
162 local_spec._min = 0;
163 if (addr_p || port_p) {
164 w.write(' ');
165 }
166 if (spec.has_numeric_type()) {
167 bwformat(w, local_spec, static_cast<uintmax_t>(addr->sa_family));
168 } else {
169 swoc::bwformat(w, local_spec, IPEndpoint::family_name(addr->sa_family));
170 }
171 }
172 return w;
173}
174
175BufferWriter &
176bwformat(BufferWriter &w, Spec const &spec, IP4Addr const &addr) {
177 in_addr_t host = addr.host_order();
178 Spec local_spec{spec}; // Format for address elements.
179 bool align_p = false;
180
181 if (spec._ext.size()) {
182 if (spec._ext.front() == '=') {
183 align_p = true;
184 local_spec._fill = '0';
185 } else if (spec._ext.size() > 1 && spec._ext[1] == '=') {
186 align_p = true;
187 local_spec._fill = spec._ext[0];
188 }
189 }
190
191 if (align_p) {
192 local_spec._min = 3;
193 local_spec._align = Spec::Align::RIGHT;
194 } else {
195 local_spec._min = 0;
196 }
197
198 bwformat(w, local_spec, static_cast<uint8_t>(host >> 24 & 0xFF));
199 w.write('.');
200 bwformat(w, local_spec, static_cast<uint8_t>(host >> 16 & 0xFF));
201 w.write('.');
202 bwformat(w, local_spec, static_cast<uint8_t>(host >> 8 & 0xFF));
203 w.write('.');
204 bwformat(w, local_spec, static_cast<uint8_t>(host & 0xFF));
205 return w;
206}
207
208BufferWriter &
209bwformat(BufferWriter &w, Spec const &spec, IP6Addr const &addr) {
210 return bwformat(w, spec, addr.network_order());
211}
212
213BufferWriter &
214bwformat(BufferWriter &w, Spec const &spec, IP4Srv const &srv) {
215 bwformat(w, spec, srv.addr());
216 if (srv.host_order_port()) {
217 w.print(":{}", srv.host_order_port());
218 }
219 return w;
220}
221
222BufferWriter &
223bwformat(BufferWriter &w, Spec const &spec, IP6Srv const &srv) {
224 auto port = srv.host_order_port();
225 if (port) {
226 w.write('[');
227 bwformat(w, spec, srv.addr());
228 w.print("]:{}", port);
229 } else {
230 bwformat(w, spec, srv.addr());
231 }
232 return w;
233}
234
235BufferWriter &
236bwformat(BufferWriter &w, Spec const &spec, IPSrv const &srv) {
237 if (srv.is_ip4()) {
238 bwformat(w, spec, IP4Srv(srv));
239 } else if (srv.is_ip6()) {
240 bwformat(w, spec, IP6Srv(srv));
241 }
242 return w;
243}
244
245BufferWriter &
246bwformat(BufferWriter &w, Spec const &spec, IPAddr const &addr) {
247 Spec local_spec{spec}; // Format for address elements and port.
248 bool addr_p{true};
249 bool family_p{false};
250
251 if (spec._ext.size()) {
252 if (spec._ext.front() == '=') {
253 local_spec._ext.remove_prefix(1);
254 } else if (spec._ext.size() > 1 && spec._ext[1] == '=') {
255 local_spec._ext.remove_prefix(2);
256 }
257 }
258 if (local_spec._ext.size()) {
259 addr_p = false;
260 for (char c : local_spec._ext) {
261 switch (c) {
262 case 'a':
263 case 'A':
264 addr_p = true;
265 break;
266 case 'f':
267 case 'F':
268 family_p = true;
269 break;
270 }
271 }
272 }
273
274 if (addr_p) {
275 if (addr.is_ip4()) {
276 swoc::bwformat(w, spec, addr.ip4());
277 } else if (addr.is_ip6()) {
278 swoc::bwformat(w, spec, addr.ip6().network_order());
279 } else {
280 w.print("*Not IP address [{}]*", addr.family());
281 }
282 }
283
284 if (family_p) {
285 local_spec._min = 0;
286 if (addr_p) {
287 w.write(' ');
288 }
289 if (spec.has_numeric_type()) {
290 bwformat(w, local_spec, static_cast<uintmax_t>(addr.family()));
291 } else {
292 swoc::bwformat(w, local_spec, addr.family());
293 }
294 }
295 return w;
296}
297
298BufferWriter &
299bwformat(BufferWriter &w, Spec const &spec, IP4Range const &range) {
300 if (range.empty()) {
301 w.write("*-*"_tv);
302 } else {
303 // Compact means output as singleton or CIDR if that's possible.
304 if (spec._ext.find('c') != spec._ext.npos) {
305 if (range.is_singleton()) {
306 return bwformat(w, spec, range.min());
307 }
308 auto mask{range.network_mask()};
309 if (mask.is_valid()) {
310 bwformat(w, spec, range.min());
311 w.write('/');
312 bwformat(w, bwf::Spec::DEFAULT, mask);
313 return w;
314 }
315 }
316 bwformat(w, spec, range.min());
317 w.write('-');
318 bwformat(w, spec, range.max());
319 }
320 return w;
321}
322
323BufferWriter &
324bwformat(BufferWriter &w, Spec const &spec, IP6Range const &range) {
325 if (range.empty()) {
326 w.write("*-*"_tv);
327 } else {
328 // Compact means output as singleton or CIDR if that's possible.
329 if (spec._ext.find('c') != spec._ext.npos) {
330 if (range.is_singleton()) {
331 return bwformat(w, spec, range.min());
332 }
333 auto mask{range.network_mask()};
334 if (mask.is_valid()) {
335 bwformat(w, spec, range.min());
336 w.write('/');
337 bwformat(w, bwf::Spec::DEFAULT, mask);
338 return w;
339 }
340 }
341 bwformat(w, spec, range.min());
342 w.write('-');
343 bwformat(w, spec, range.max());
344 }
345 return w;
346}
347
348BufferWriter &
349bwformat(BufferWriter &w, Spec const &spec, IPRange const &range) {
350 return range.is(AF_INET) ? bwformat(w, spec, range.ip4()) :
351 range.is(AF_INET6) ? bwformat(w, spec, range.ip6()) :
352 w.write("*-*"_tv);
353}
354
355BufferWriter &
356bwformat(BufferWriter &w, Spec const &spec, IPRangeView const &rv) {
357 return rv.is(AF_INET) ? bwformat(w, spec, rv.ip4()) : rv.is(AF_INET6) ? bwformat(w, spec, rv.ip6()) : w.write("*-*"_tv);
358}
359
360BufferWriter &
361bwformat(BufferWriter &w, Spec const &spec, IP4Net const &net) {
362 bwformat(w, spec, net.min());
363 w.write('/');
364 bwformat(w, Spec{}, net.mask().width());
365 return w;
366}
367
368BufferWriter &
369bwformat(BufferWriter &w, Spec const &spec, IP6Net const &net) {
370 bwformat(w, spec, net.min());
371 w.write('/');
372 bwformat(w, Spec{}, net.mask().width());
373 return w;
374}
375
376BufferWriter &
377bwformat(BufferWriter &w, Spec const &spec, IPNet const &net) {
378 if (net.is_ip6()) {
379 return bwformat(w, spec, net.ip6());
380 } else if (net.is_ip4()) {
381 return bwformat(w, spec, net.ip4());
382 }
383 return w.write("*invalid*");
384}
385
386BufferWriter &
387bwformat(BufferWriter &w, Spec const &spec, IPMask const &mask) {
388 return bwformat(w, spec, mask.width());
389}
390
391}} // namespace swoc::SWOC_VERSION_NS
BufferWriter & print(const TextView &fmt, Args &&...args)
Definition bwf_base.h:927
virtual BufferWriter & write(char c)=0
metric_type const & max() const
bool is_singleton() const
Check if the interval is exactly one element.
metric_type const & min() const
in_addr_t host_order() const
Definition IPAddr.h:820
IPMask const & mask() const
Definition IPRange.h:2123
IP4Addr min() const
Definition IPRange.h:2133
IPMask network_mask() const
Definition swoc_ip.cc:983
constexpr IP4Addr const & addr() const
Definition IPSrv.h:433
in_port_t host_order_port() const
Definition IPSrv.h:437
in6_addr network_order() const
Return the address in network order.
Definition IPAddr.h:997
IP6Addr min() const
Definition IPRange.h:2177
IPMask const & mask() const
Definition IPRange.h:2167
IPMask network_mask() const
Definition swoc_ip.cc:1192
in_port_t host_order_port() const
Definition IPSrv.h:488
constexpr IP6Addr const & addr() const
Definition IPSrv.h:484
bool is_ip6() const
Test for IPv6.
Definition IPAddr.h:1274
bool is_ip4() const
Test for IPv4.
Definition IPAddr.h:1269
IP6Addr const & ip6() const
Definition IPAddr.h:1377
IP4Addr const & ip4() const
Definition IPAddr.h:1369
sa_family_t family() const
Definition IPAddr.h:1264
raw_type width() const
The width of the mask.
Definition IPAddr.h:1143
IP6Net ip6() const
Definition IPRange.h:2287
IP4Net ip4() const
Definition IPRange.h:2282
bool is_ip6() const
Definition IPRange.h:922
bool is_ip4() const
Definition IPRange.h:916
bool is(sa_family_t family) const
Definition IPRange.h:2032
IP4Range const & ip4() const
Definition IPRange.h:2057
IP4Range const & ip4() const
Definition IPRange.h:1996
bool is(sa_family_t family) const
Definition IPRange.h:1974
bool is_ip4() const
Definition IPSrv.h:572
bool is_ip6() const
Definition IPSrv.h:577
For template deduction guides.
Definition ArenaWriter.cc:9
BufferWriter & bwformat(BufferWriter &w, bwf::Spec const &spec, std::string_view sv)
Definition bw_format.cc:649
char _type
Type / radix indicator.
Definition bwf_base.h:69
bool has_numeric_type() const
Check if the type in this is numeric.
Definition bwf_base.h:507
std::string_view _ext
Extension if provided.
Definition bwf_base.h:77