jaulib v1.4.0-2-g788cf73
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
eui48.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 * Copyright (c) 2020 ZAFENA AB
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26#ifndef JAU_EUI48_HPP_
27#define JAU_EUI48_HPP_
28
29#include <cstring>
30#include <string>
31#include <cstdint>
32
33#include <jau/basic_types.hpp>
35
36namespace jau::io::net {
37
38 /** @defgroup NetUtils Network Utilities
39 * Networking types and functionality.
40 *
41 * @{
42 */
43
44 /**
45 * A 48 bit EUI-48 sub-identifier, see EUI48.
46 *
47 * Stores value in lb_endian::native byte order.
48 */
49 struct EUI48Sub {
50 public:
51 /** EUI48 MAC address matching any device, i.e. `0:0:0:0:0:0`. */
52 static const EUI48Sub ANY_DEVICE;
53 /** EUI48 MAC address matching all device, i.e. `ff:ff:ff:ff:ff:ff`. */
54 static const EUI48Sub ALL_DEVICE;
55 /** EUI48 MAC address matching local device, i.e. `0:0:0:ff:ff:ff`. */
56 static const EUI48Sub LOCAL_DEVICE;
57
58 /**
59 * The <= 6 byte EUI48 sub-address.
60 */
61 uint8_t b[6]; // == sizeof(EUI48)
62
63 /**
64 * The actual length in bytes of the EUI48 sub-address, less or equal 6 bytes.
65 */
67
68 constexpr EUI48Sub() noexcept : b{0}, length{0} { }
69
70 /**
71 * Copy len_ address bytes from given source and byte_order,
72 * while converting them to lb_endian::native byte order.
73 *
74 * @param b_ sub address bytes in lb_endian::native byte order
75 * @param len_ length
76 * @param byte_order lb_endian::little or lb_endian::big byte order of given sub_address, one may pass lb_endian::native.
77 */
78 EUI48Sub(const uint8_t * b_, const jau::nsize_t len_, const lb_endian_t byte_order) noexcept;
79
80 /**
81 * Fills given EUI48Sub instance via given string representation.
82 * <p>
83 * Implementation is consistent with EUI48Sub::toString().
84 * </p>
85 * @param str a string of less or equal of 17 characters representing less or equal of 6 bytes as hexadecimal numbers separated via colon,
86 * e.g. `01:02:03:0A:0B:0C`, `01:02:03:0A`, `:`, (empty).
87 * @param dest EUI48Sub to set its value
88 * @param errmsg error parsing message if returning false
89 * @return true if successful, otherwise false
90 * @see EUI48Sub::EUI48Sub
91 * @see EUI48Sub::toString()
92 */
93 static bool scanEUI48Sub(const std::string& str, EUI48Sub& dest, std::string& errmsg);
94
95 /**
96 * Construct a sub EUI48 via given string representation.
97 * <p>
98 * Implementation is consistent with EUI48Sub::toString().
99 * </p>
100 * @param str a string of less or equal of 17 characters representing less or equal of 6 bytes as hexadecimal numbers separated via colon,
101 * e.g. `01:02:03:0A:0B:0C`, `01:02:03:0A`, `:`, (empty).
102 * @see EUI48Sub::scanEUI48Sub()
103 * @see EUI48Sub::toString()
104 * @throws jau::IllegalArgumentException if given string doesn't comply with EUI48
105 */
106 EUI48Sub(const std::string& str);
107
108 constexpr EUI48Sub(const EUI48Sub &o) noexcept = default;
109 EUI48Sub(EUI48Sub &&o) noexcept = default;
110 constexpr EUI48Sub& operator=(const EUI48Sub &o) noexcept = default;
111 EUI48Sub& operator=(EUI48Sub &&o) noexcept = default;
112
113 constexpr std::size_t hash_code() const noexcept {
114 // 31 * x == (x << 5) - x
115 std::size_t h = length;
116 for(jau::nsize_t i=0; i<length; i++) {
117 h = ( ( h << 5 ) - h ) + b[i];
118 }
119 return h;
120 }
121
122 /**
123 * Method clears the underlying byte array {@link #b} and sets length to zero.
124 */
125 void clear() {
126 b[0] = 0; b[1] = 0; b[2] = 0;
127 b[3] = 0; b[4] = 0; b[5] = 0;
128 length = 0;
129 }
130
131 /**
132 * Find index of needle within haystack in the given byte order.
133 *
134 * The returned index will be adjusted for the desired byte order.
135 * - lb_endian::big will return index 0 for the leading byte like the toString() representation from left (MSB) to right (LSB).
136 * - lb_endian::little will return index 5 for the leading byte
137 *
138 * @param haystack_b haystack data
139 * @param haystack_length haystack length
140 * @param needle_b needle data
141 * @param needle_length needle length
142 * @param byte_order byte order will adjust the returned index, lb_endian::big is equivalent with toString() representation from left (MSB) to right (LSB).
143 * @return index of first element of needle within haystack or -1 if not found. If the needle length is zero, 0 (found) is returned.
144 */
145 static jau::snsize_t indexOf(const uint8_t haystack_b[], const jau::nsize_t haystack_length,
146 const uint8_t needle_b[], const jau::nsize_t needle_length,
147 const lb_endian_t byte_order) noexcept;
148
149 /**
150 * Finds the index of given EUI48Sub needle within this instance haystack in the given byte order.
151 *
152 * The returned index will be adjusted for the desired byte order.
153 * - lb_endian::big will return index 0 for the leading byte like the toString() representation from left (MSB) to right (LSB).
154 * - lb_endian::little will return index 5 for the leading byte
155 *
156 * @param needle
157 * @param byte_order byte order will adjust the returned index, lb_endian::big is equivalent with toString() representation from left (MSB) to right (LSB).
158 * @return index of first element of needle within this instance haystack or -1 if not found. If the needle length is zero, 0 (found) is returned.
159 * @see indexOf()
160 */
161 jau::snsize_t indexOf(const EUI48Sub& needle, const lb_endian_t byte_order) const noexcept {
162 return indexOf(b, length, needle.b, needle.length, byte_order);
163 }
164
165 /**
166 * Returns true, if given EUI48Sub needle is contained in this instance haystack.
167 * <p>
168 * If the sub is zero, true is returned.
169 * </p>
170 */
171 bool contains(const EUI48Sub& needle) const noexcept {
172 return 0 <= indexOf(needle, lb_endian_t::native);
173 }
174
175 /**
176 * Returns the EUI48 sub-string representation with MSB first (lb_endian::big),
177 * less or equal 17 characters representing less or equal 6 bytes as upper case hexadecimal numbers separated via colon,
178 * e.g. `01:02:03:0A:0B:0C`, `01:02:03:0A`, `:`, (empty).
179 */
180 std::string toString() const noexcept;
181 };
182 inline std::string to_string(const EUI48Sub& a) noexcept { return a.toString(); }
183
184 inline bool operator==(const EUI48Sub& lhs, const EUI48Sub& rhs) noexcept {
185 if( &lhs == &rhs ) {
186 return true;
187 }
188 if( lhs.length != rhs.length ) {
189 return false;
190 }
191 return !memcmp(&lhs.b, &rhs.b, lhs.length);
192 }
193
194 inline bool operator!=(const EUI48Sub& lhs, const EUI48Sub& rhs) noexcept
195 { return !(lhs == rhs); }
196
197
198 /**
199 * A packed 48 bit EUI-48 identifier, formerly known as MAC-48
200 * or simply network device MAC address (Media Access Control address).
201 *
202 * Stores value in lb_endian::native byte order.
203 */
204 __pack ( struct EUI48 {
205 /** EUI48 MAC address matching any device, i.e. `0:0:0:0:0:0`. */
206 static const EUI48 ANY_DEVICE;
207 /** EUI48 MAC address matching all device, i.e. `ff:ff:ff:ff:ff:ff`. */
208 static const EUI48 ALL_DEVICE;
209 /** EUI48 MAC address matching local device, i.e. `0:0:0:ff:ff:ff`. */
210 static const EUI48 LOCAL_DEVICE;
211
212 /**
213 * The 6 byte EUI48 address.
214 */
215 uint8_t b[6]; // == sizeof(EUI48)
216
217 constexpr EUI48() noexcept : b{0} { }
218
219 /**
220 * Copy address bytes from given source and byte_order,
221 * while converting them to lb_endian::native byte order.
222 *
223 * @param source address bytes
224 * @param byte_order lb_endian::little or lb_endian::big byte order of given source, one may pass lb_endian::native.
225 */
226 EUI48(const uint8_t * source, const lb_endian_t byte_order) noexcept;
227
228 /**
229 * Fills given EUI48 instance via given string representation.
230 * <p>
231 * Implementation is consistent with EUI48::toString().
232 * </p>
233 * @param str a string of exactly 17 characters representing 6 bytes as hexadecimal numbers separated via colon `01:02:03:0A:0B:0C`.
234 * @param dest EUI48 to set its value
235 * @param errmsg error parsing message if returning false
236 * @return true if successful, otherwise false
237 * @see EUI48::EUI48
238 * @see EUI48::toString()
239 */
240 static bool scanEUI48(const std::string& str, EUI48& dest, std::string& errmsg);
241
242 /**
243 * Construct instance via given string representation.
244 * <p>
245 * Implementation is consistent with EUI48::toString().
246 * </p>
247 * @param str a string of exactly 17 characters representing 6 bytes as hexadecimal numbers separated via colon `01:02:03:0A:0B:0C`.
248 * @see EUI48::scanEUI48()
249 * @see EUI48::toString()
250 * @throws jau::IllegalArgumentException if given string doesn't comply with EUI48
251 */
252 EUI48(const std::string& str);
253
254 constexpr EUI48(const EUI48 &o) noexcept = default;
255 EUI48(EUI48 &&o) noexcept = default;
256 constexpr EUI48& operator=(const EUI48 &o) noexcept = default;
257 EUI48& operator=(EUI48 &&o) noexcept = default;
258
259 constexpr std::size_t hash_code() const noexcept {
260 // 31 * x == (x << 5) - x
261 std::size_t h = b[0];
262 h = ( ( h << 5 ) - h ) + b[1];
263 h = ( ( h << 5 ) - h ) + b[2];
264 h = ( ( h << 5 ) - h ) + b[3];
265 h = ( ( h << 5 ) - h ) + b[4];
266 h = ( ( h << 5 ) - h ) + b[5];
267 return h;
268 }
269
270 /**
271 * Method clears the underlying byte array {@link #b}.
272 */
273 void clear() {
274 b[0] = 0; b[1] = 0; b[2] = 0;
275 b[3] = 0; b[4] = 0; b[5] = 0;
276 }
277
278 /**
279 * Finds the index of given EUI48Sub needle within this instance haystack.
280 *
281 * The returned index will be adjusted for the desired byte order.
282 * - lb_endian::big will return index 0 for the leading byte like the string representation from left (MSB) to right (LSB).
283 * - lb_endian::little will return index 5 for the leading byte
284 *
285 * @param needle
286 * @param byte_order byte order will adjust the returned index, lb_endian::big is equivalent to the string representation from left (MSB) to right (LSB).
287 * @return index of first element of needle within this instance haystack or -1 if not found. If the needle length is zero, 0 (found) is returned.
288 * @see indexOf()
289 */
290 jau::snsize_t indexOf(const EUI48Sub& needle, const lb_endian_t byte_order) const noexcept {
291 return EUI48Sub::indexOf(b, sizeof(b), needle.b, needle.length, byte_order);
292 }
293
294 /**
295 * Returns true, if given EUI48Sub needle is contained in this instance haystack.
296 * <p>
297 * If the sub is zero, true is returned.
298 * </p>
299 */
300 bool contains(const EUI48Sub& needle) const noexcept {
301 return 0 <= indexOf(needle, lb_endian_t::native);
302 }
303
304 /**
305 * Returns the EUI48 string representation with MSB first (lb_endian::big),
306 * exactly 17 characters representing 6 bytes as upper case hexadecimal numbers separated via colon `01:02:03:0A:0B:0C`.
307 * @see EUI48::EUI48()
308 */
309 std::string toString() const noexcept;
310
311 /**
312 * Method transfers all bytes representing this instance into the given
313 * destination array at the given position and in the given byte order.
314 * <p>
315 * Implementation is consistent with {@link #EUI48(byte[], int, ByteOrder)}.
316 * </p>
317 * @param sink the destination array
318 * @param byte_order destination buffer byte order
319 * @see #EUI48(byte[], int, ByteOrder)
320 */
321 jau::nsize_t put(uint8_t * const sink, const lb_endian_t byte_order) const noexcept;
322 } );
323 inline std::string to_string(const EUI48& a) noexcept { return a.toString(); }
324
325 inline bool operator==(const EUI48& lhs, const EUI48& rhs) noexcept {
326 if( &lhs == &rhs ) {
327 return true;
328 }
329 //return !memcmp(&lhs, &rhs, sizeof(EUI48));
330 const uint8_t * a = lhs.b;
331 const uint8_t * b = rhs.b;
332 return a[0] == b[0] &&
333 a[1] == b[1] &&
334 a[2] == b[2] &&
335 a[3] == b[3] &&
336 a[4] == b[4] &&
337 a[5] == b[5];
338 }
339
340 inline bool operator!=(const EUI48& lhs, const EUI48& rhs) noexcept
341 { return !(lhs == rhs); }
342
343 constexpr static void bswap_6bytes(uint8_t* sink, const uint8_t* source) noexcept {
344 sink[0] = source[5];
345 sink[1] = source[4];
346 sink[2] = source[3];
347 sink[3] = source[2];
348 sink[4] = source[1];
349 sink[5] = source[0];
350 }
351
352 constexpr EUI48 bswap(EUI48 const & source) noexcept {
353 EUI48 dest;
354 bswap_6bytes(dest.b, source.b);
355 return dest;
356 }
357
358 // one static_assert is sufficient for whole compilation unit
359 static_assert( is_defined_endian(endian_t::native) );
360 static_assert( is_little_or_big_endian() );
361
362 constexpr EUI48 be_to_cpu(EUI48 const & n) noexcept {
363 if( is_little_endian() ) {
364 return bswap(n);
365 } else {
366 return n;
367 }
368 }
369 constexpr EUI48 cpu_to_be(EUI48 const & h) noexcept {
370 if( is_little_endian() ) {
371 return bswap(h);
372 } else {
373 return h;
374 }
375 }
376 constexpr EUI48 le_to_cpu(EUI48 const & l) noexcept {
377 if( is_little_endian() ) {
378 return l;
379 } else {
380 return bswap(l);
381 }
382 }
383 constexpr EUI48 cpu_to_le(EUI48 const & h) noexcept {
384 if( is_little_endian() ) {
385 return h;
386 } else {
387 return bswap(h);
388 }
389 }
390
391 /**@}*/
392
393} /* namespace jau::io::net */
394
395// injecting specialization of std::hash to namespace std of our types above
396namespace std
397{
398 /** \addtogroup NetUtils
399 *
400 */
401
402 template<> struct hash<jau::io::net::EUI48Sub> {
403 std::size_t operator()(jau::io::net::EUI48Sub const& a) const noexcept {
404 return a.hash_code();
405 }
406 };
407
408 template<> struct hash<jau::io::net::EUI48> {
409 std::size_t operator()(jau::io::net::EUI48 const& a) const noexcept {
410 return a.hash_code();
411 }
412 };
413
414 /**@}*/
415}
416
417#endif /* JAU_EUI48_HPP_ */
constexpr bool is_little_endian() noexcept
Evaluates true if platform is running in little endian mode, i.e.
constexpr bool is_defined_endian(const endian_t &v) noexcept
Evaluates true if the given endian is defined, i.e.
constexpr bool is_little_or_big_endian() noexcept
Evaluates true if platform is running in little or big endian mode, i.e.
lb_endian_t
Simplified reduced endian type only covering little- and big-endian.
@ native
Identifier for native platform type, one of the above.
@ native
Identifier for native platform type, one of the above.
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition int_types.hpp:55
int_fast32_t snsize_t
Natural 'ssize_t' alternative using int_fast32_t as its natural sized type.
Definition int_types.hpp:67
bool operator!=(const EUI48Sub &lhs, const EUI48Sub &rhs) noexcept
Definition eui48.hpp:194
constexpr EUI48 cpu_to_le(EUI48 const &h) noexcept
Definition eui48.hpp:383
static constexpr void bswap_6bytes(uint8_t *sink, const uint8_t *source) noexcept
Definition eui48.hpp:343
constexpr EUI48 cpu_to_be(EUI48 const &h) noexcept
Definition eui48.hpp:369
constexpr EUI48 bswap(EUI48 const &source) noexcept
Definition eui48.hpp:352
std::string to_string(const EUI48Sub &a) noexcept
Definition eui48.hpp:182
constexpr EUI48 le_to_cpu(EUI48 const &l) noexcept
Definition eui48.hpp:376
constexpr EUI48 be_to_cpu(EUI48 const &n) noexcept
Definition eui48.hpp:362
bool operator==(const EUI48Sub &lhs, const EUI48Sub &rhs) noexcept
Definition eui48.hpp:184
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
STL namespace.
A 48 bit EUI-48 sub-identifier, see EUI48.
Definition eui48.hpp:49
constexpr std::size_t hash_code() const noexcept
Definition eui48.hpp:113
uint8_t b[6]
The <= 6 byte EUI48 sub-address.
Definition eui48.hpp:61
jau::nsize_t length
The actual length in bytes of the EUI48 sub-address, less or equal 6 bytes.
Definition eui48.hpp:66
constexpr EUI48Sub() noexcept
Definition eui48.hpp:68
EUI48Sub(EUI48Sub &&o) noexcept=default
constexpr EUI48Sub(const EUI48Sub &o) noexcept=default
static const EUI48Sub ANY_DEVICE
EUI48 MAC address matching any device, i.e.
Definition eui48.hpp:52
void clear()
Method clears the underlying byte array b and sets length to zero.
Definition eui48.hpp:125
bool contains(const EUI48Sub &needle) const noexcept
Returns true, if given EUI48Sub needle is contained in this instance haystack.
Definition eui48.hpp:171
static jau::snsize_t indexOf(const uint8_t haystack_b[], const jau::nsize_t haystack_length, const uint8_t needle_b[], const jau::nsize_t needle_length, const lb_endian_t byte_order) noexcept
Find index of needle within haystack in the given byte order.
Definition eui48.cpp:132
static const EUI48Sub LOCAL_DEVICE
EUI48 MAC address matching local device, i.e.
Definition eui48.hpp:56
EUI48Sub & operator=(EUI48Sub &&o) noexcept=default
jau::snsize_t indexOf(const EUI48Sub &needle, const lb_endian_t byte_order) const noexcept
Finds the index of given EUI48Sub needle within this instance haystack in the given byte order.
Definition eui48.hpp:161
constexpr EUI48Sub & operator=(const EUI48Sub &o) noexcept=default
std::string toString() const noexcept
Returns the EUI48 sub-string representation with MSB first (lb_endian::big), less or equal 17 charact...
Definition eui48.cpp:39
static const EUI48Sub ALL_DEVICE
EUI48 MAC address matching all device, i.e.
Definition eui48.hpp:54
static bool scanEUI48Sub(const std::string &str, EUI48Sub &dest, std::string &errmsg)
Fills given EUI48Sub instance via given string representation.
Definition eui48.cpp:69
A packed 48 bit EUI-48 identifier, formerly known as MAC-48 or simply network device MAC address (Med...
Definition eui48.hpp:322
std::size_t operator()(jau::io::net::EUI48Sub const &a) const noexcept
Definition eui48.hpp:403
std::size_t operator()(jau::io::net::EUI48 const &a) const noexcept
Definition eui48.hpp:409