Direct-BT v3.3.0-1-gc2d430c
Direct-BT - Direct Bluetooth Programming.
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 <memory>
32#include <cstdint>
33#include <vector>
34
35#include <jau/basic_types.hpp>
37
38namespace jau {
39
40 /** @defgroup NetUtils Network Utilities
41 * Networking types and functionality.
42 *
43 * @{
44 */
45
46 /**
47 * A 48 bit EUI-48 sub-identifier, see EUI48.
48 *
49 * Stores value in lb_endian::native byte order.
50 */
51 struct EUI48Sub {
52 public:
53 /** EUI48 MAC address matching any device, i.e. `0:0:0:0:0:0`. */
54 static const EUI48Sub ANY_DEVICE;
55 /** EUI48 MAC address matching all device, i.e. `ff:ff:ff:ff:ff:ff`. */
56 static const EUI48Sub ALL_DEVICE;
57 /** EUI48 MAC address matching local device, i.e. `0:0:0:ff:ff:ff`. */
58 static const EUI48Sub LOCAL_DEVICE;
59
60 /**
61 * The <= 6 byte EUI48 sub-address.
62 */
63 uint8_t b[6]; // == sizeof(EUI48)
64
65 /**
66 * The actual length in bytes of the EUI48 sub-address, less or equal 6 bytes.
67 */
69
70 constexpr EUI48Sub() noexcept : b{0}, length{0} { }
71
72 /**
73 * Copy len_ address bytes from given source and byte_order,
74 * while converting them to lb_endian::native byte order.
75 *
76 * @param b_ sub address bytes in lb_endian::native byte order
77 * @param len_ length
78 * @param byte_order lb_endian::little or lb_endian::big byte order of given sub_address, one may pass lb_endian::native.
79 */
80 EUI48Sub(const uint8_t * b_, const jau::nsize_t len_, const lb_endian_t byte_order) noexcept;
81
82 /**
83 * Fills given EUI48Sub instance via given string representation.
84 * <p>
85 * Implementation is consistent with EUI48Sub::toString().
86 * </p>
87 * @param str a string of less or equal of 17 characters representing less or equal of 6 bytes as hexadecimal numbers separated via colon,
88 * e.g. `01:02:03:0A:0B:0C`, `01:02:03:0A`, `:`, (empty).
89 * @param dest EUI48Sub to set its value
90 * @param errmsg error parsing message if returning false
91 * @return true if successful, otherwise false
92 * @see EUI48Sub::EUI48Sub
93 * @see EUI48Sub::toString()
94 */
95 static bool scanEUI48Sub(const std::string& str, EUI48Sub& dest, std::string& errmsg);
96
97 /**
98 * Construct a sub EUI48 via given string representation.
99 * <p>
100 * Implementation is consistent with EUI48Sub::toString().
101 * </p>
102 * @param str a string of less or equal of 17 characters representing less or equal of 6 bytes as hexadecimal numbers separated via colon,
103 * e.g. `01:02:03:0A:0B:0C`, `01:02:03:0A`, `:`, (empty).
104 * @see EUI48Sub::scanEUI48Sub()
105 * @see EUI48Sub::toString()
106 * @throws jau::IllegalArgumentException if given string doesn't comply with EUI48
107 */
108 EUI48Sub(const std::string& str);
109
110 constexpr EUI48Sub(const EUI48Sub &o) noexcept = default;
111 EUI48Sub(EUI48Sub &&o) noexcept = default;
112 constexpr EUI48Sub& operator=(const EUI48Sub &o) noexcept = default;
113 EUI48Sub& operator=(EUI48Sub &&o) noexcept = default;
114
115 constexpr std::size_t hash_code() const noexcept {
116 // 31 * x == (x << 5) - x
117 std::size_t h = length;
118 for(jau::nsize_t i=0; i<length; i++) {
119 h = ( ( h << 5 ) - h ) + b[i];
120 }
121 return h;
122 }
123
124 /**
125 * Method clears the underlying byte array {@link #b} and sets length to zero.
126 */
127 void clear() {
128 b[0] = 0; b[1] = 0; b[2] = 0;
129 b[3] = 0; b[4] = 0; b[5] = 0;
130 length = 0;
131 }
132
133 /**
134 * Find index of needle within haystack in the given byte order.
135 *
136 * The returned index will be adjusted for the desired byte order.
137 * - lb_endian::big will return index 0 for the leading byte like the toString() representation from left (MSB) to right (LSB).
138 * - lb_endian::little will return index 5 for the leading byte
139 *
140 * @param haystack_b haystack data
141 * @param haystack_length haystack length
142 * @param needle_b needle data
143 * @param needle_length needle length
144 * @param byte_order byte order will adjust the returned index, lb_endian::big is equivalent with toString() representation from left (MSB) to right (LSB).
145 * @return index of first element of needle within haystack or -1 if not found. If the needle length is zero, 0 (found) is returned.
146 */
147 static jau::snsize_t indexOf(const uint8_t haystack_b[], const jau::nsize_t haystack_length,
148 const uint8_t needle_b[], const jau::nsize_t needle_length,
149 const lb_endian_t byte_order) noexcept;
150
151 /**
152 * Finds the index of given EUI48Sub needle within this instance haystack in the given byte order.
153 *
154 * The returned index will be adjusted for the desired byte order.
155 * - lb_endian::big will return index 0 for the leading byte like the toString() representation from left (MSB) to right (LSB).
156 * - lb_endian::little will return index 5 for the leading byte
157 *
158 * @param needle
159 * @param byte_order byte order will adjust the returned index, lb_endian::big is equivalent with toString() representation from left (MSB) to right (LSB).
160 * @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.
161 * @see indexOf()
162 */
163 jau::snsize_t indexOf(const EUI48Sub& needle, const lb_endian_t byte_order) const noexcept {
164 return indexOf(b, length, needle.b, needle.length, byte_order);
165 }
166
167 /**
168 * Returns true, if given EUI48Sub needle is contained in this instance haystack.
169 * <p>
170 * If the sub is zero, true is returned.
171 * </p>
172 */
173 bool contains(const EUI48Sub& needle) const noexcept {
174 return 0 <= indexOf(needle, lb_endian_t::native);
175 }
176
177 /**
178 * Returns the EUI48 sub-string representation with MSB first (lb_endian::big),
179 * less or equal 17 characters representing less or equal 6 bytes as upper case hexadecimal numbers separated via colon,
180 * e.g. `01:02:03:0A:0B:0C`, `01:02:03:0A`, `:`, (empty).
181 */
182 std::string toString() const noexcept;
183 };
184 inline std::string to_string(const EUI48Sub& a) noexcept { return a.toString(); }
185
186 inline bool operator==(const EUI48Sub& lhs, const EUI48Sub& rhs) noexcept {
187 if( &lhs == &rhs ) {
188 return true;
189 }
190 if( lhs.length != rhs.length ) {
191 return false;
192 }
193 return !memcmp(&lhs.b, &rhs.b, lhs.length);
194 }
195
196 inline bool operator!=(const EUI48Sub& lhs, const EUI48Sub& rhs) noexcept
197 { return !(lhs == rhs); }
198
199
200 /**
201 * A packed 48 bit EUI-48 identifier, formerly known as MAC-48
202 * or simply network device MAC address (Media Access Control address).
203 *
204 * Stores value in lb_endian::native byte order.
205 */
206 __pack ( struct EUI48 {
207 /** EUI48 MAC address matching any device, i.e. `0:0:0:0:0:0`. */
208 static const EUI48 ANY_DEVICE;
209 /** EUI48 MAC address matching all device, i.e. `ff:ff:ff:ff:ff:ff`. */
210 static const EUI48 ALL_DEVICE;
211 /** EUI48 MAC address matching local device, i.e. `0:0:0:ff:ff:ff`. */
212 static const EUI48 LOCAL_DEVICE;
213
214 /**
215 * The 6 byte EUI48 address.
216 */
217 uint8_t b[6]; // == sizeof(EUI48)
218
219 constexpr EUI48() noexcept : b{0} { }
220
221 /**
222 * Copy address bytes from given source and byte_order,
223 * while converting them to lb_endian::native byte order.
224 *
225 * @param source address bytes
226 * @param byte_order lb_endian::little or lb_endian::big byte order of given source, one may pass lb_endian::native.
227 */
228 EUI48(const uint8_t * source, const lb_endian_t byte_order) noexcept;
229
230 /**
231 * Fills given EUI48 instance via given string representation.
232 * <p>
233 * Implementation is consistent with EUI48::toString().
234 * </p>
235 * @param str a string of exactly 17 characters representing 6 bytes as hexadecimal numbers separated via colon `01:02:03:0A:0B:0C`.
236 * @param dest EUI48 to set its value
237 * @param errmsg error parsing message if returning false
238 * @return true if successful, otherwise false
239 * @see EUI48::EUI48
240 * @see EUI48::toString()
241 */
242 static bool scanEUI48(const std::string& str, EUI48& dest, std::string& errmsg);
243
244 /**
245 * Construct instance via given string representation.
246 * <p>
247 * Implementation is consistent with EUI48::toString().
248 * </p>
249 * @param str a string of exactly 17 characters representing 6 bytes as hexadecimal numbers separated via colon `01:02:03:0A:0B:0C`.
250 * @see EUI48::scanEUI48()
251 * @see EUI48::toString()
252 * @throws jau::IllegalArgumentException if given string doesn't comply with EUI48
253 */
254 EUI48(const std::string& str);
255
256 constexpr EUI48(const EUI48 &o) noexcept = default;
257 EUI48(EUI48 &&o) noexcept = default;
258 constexpr EUI48& operator=(const EUI48 &o) noexcept = default;
259 EUI48& operator=(EUI48 &&o) noexcept = default;
260
261 constexpr std::size_t hash_code() const noexcept {
262 // 31 * x == (x << 5) - x
263 std::size_t h = b[0];
264 h = ( ( h << 5 ) - h ) + b[1];
265 h = ( ( h << 5 ) - h ) + b[2];
266 h = ( ( h << 5 ) - h ) + b[3];
267 h = ( ( h << 5 ) - h ) + b[4];
268 h = ( ( h << 5 ) - h ) + b[5];
269 return h;
270 }
271
272 /**
273 * Method clears the underlying byte array {@link #b}.
274 */
275 void clear() {
276 b[0] = 0; b[1] = 0; b[2] = 0;
277 b[3] = 0; b[4] = 0; b[5] = 0;
278 }
279
280 /**
281 * Finds the index of given EUI48Sub needle within this instance haystack.
282 *
283 * The returned index will be adjusted for the desired byte order.
284 * - lb_endian::big will return index 0 for the leading byte like the string representation from left (MSB) to right (LSB).
285 * - lb_endian::little will return index 5 for the leading byte
286 *
287 * @param needle
288 * @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).
289 * @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.
290 * @see indexOf()
291 */
292 jau::snsize_t indexOf(const EUI48Sub& needle, const lb_endian_t byte_order) const noexcept {
293 return EUI48Sub::indexOf(b, sizeof(b), needle.b, needle.length, byte_order);
294 }
295
296 /**
297 * Returns true, if given EUI48Sub needle is contained in this instance haystack.
298 * <p>
299 * If the sub is zero, true is returned.
300 * </p>
301 */
302 bool contains(const EUI48Sub& needle) const noexcept {
303 return 0 <= indexOf(needle, lb_endian_t::native);
304 }
305
306 /**
307 * Returns the EUI48 string representation with MSB first (lb_endian::big),
308 * exactly 17 characters representing 6 bytes as upper case hexadecimal numbers separated via colon `01:02:03:0A:0B:0C`.
309 * @see EUI48::EUI48()
310 */
311 std::string toString() const noexcept;
312
313 /**
314 * Method transfers all bytes representing this instance into the given
315 * destination array at the given position and in the given byte order.
316 * <p>
317 * Implementation is consistent with {@link #EUI48(byte[], int, ByteOrder)}.
318 * </p>
319 * @param sink the destination array
320 * @param byte_order destination buffer byte order
321 * @see #EUI48(byte[], int, ByteOrder)
322 */
323 jau::nsize_t put(uint8_t * const sink, const lb_endian_t byte_order) const noexcept;
324 } );
325 inline std::string to_string(const EUI48& a) noexcept { return a.toString(); }
326
327 inline bool operator==(const EUI48& lhs, const EUI48& rhs) noexcept {
328 if( &lhs == &rhs ) {
329 return true;
330 }
331 //return !memcmp(&lhs, &rhs, sizeof(EUI48));
332 const uint8_t * a = lhs.b;
333 const uint8_t * b = rhs.b;
334 return a[0] == b[0] &&
335 a[1] == b[1] &&
336 a[2] == b[2] &&
337 a[3] == b[3] &&
338 a[4] == b[4] &&
339 a[5] == b[5];
340 }
341
342 inline bool operator!=(const EUI48& lhs, const EUI48& rhs) noexcept
343 { return !(lhs == rhs); }
344
345 constexpr static void bswap_6bytes(uint8_t* sink, const uint8_t* source) noexcept {
346 sink[0] = source[5];
347 sink[1] = source[4];
348 sink[2] = source[3];
349 sink[3] = source[2];
350 sink[4] = source[1];
351 sink[5] = source[0];
352 }
353
354 constexpr EUI48 bswap(EUI48 const & source) noexcept {
355 EUI48 dest;
356 bswap_6bytes(dest.b, source.b);
357 return dest;
358 }
359
360 // one static_assert is sufficient for whole compilation unit
361 static_assert( is_defined_endian(endian_t::native) );
362 static_assert( is_little_or_big_endian() );
363
364 constexpr EUI48 be_to_cpu(EUI48 const & n) noexcept {
365 if( is_little_endian() ) {
366 return bswap(n);
367 } else {
368 return n;
369 }
370 }
371 constexpr EUI48 cpu_to_be(EUI48 const & h) noexcept {
372 if( is_little_endian() ) {
373 return bswap(h);
374 } else {
375 return h;
376 }
377 }
378 constexpr EUI48 le_to_cpu(EUI48 const & l) noexcept {
379 if( is_little_endian() ) {
380 return l;
381 } else {
382 return bswap(l);
383 }
384 }
385 constexpr EUI48 cpu_to_le(EUI48 const & h) noexcept {
386 if( is_little_endian() ) {
387 return h;
388 } else {
389 return bswap(h);
390 }
391 }
392
393 /**@}*/
394
395} /* namespace jau */
396
397// injecting specialization of std::hash to namespace std of our types above
398namespace std
399{
400 /** \addtogroup NetUtils
401 *
402 */
403
404 template<> struct hash<jau::EUI48Sub> {
405 std::size_t operator()(jau::EUI48Sub const& a) const noexcept {
406 return a.hash_code();
407 }
408 };
409
410 template<> struct hash<jau::EUI48> {
411 std::size_t operator()(jau::EUI48 const& a) const noexcept {
412 return a.hash_code();
413 }
414 };
415
416 /**@}*/
417}
418
419#endif /* JAU_EUI48_HPP_ */
constexpr bool is_defined_endian(const endian_t &v) noexcept
Evaluates true if the given endian is defined, i.e.
Definition: byte_util.hpp:275
constexpr uint16_t bswap(uint16_t const source) noexcept
Definition: byte_util.hpp:88
constexpr bool is_little_or_big_endian() noexcept
Evaluates true if platform is running in little or big endian mode, i.e.
Definition: byte_util.hpp:324
constexpr uint16_t cpu_to_be(uint16_t const h) noexcept
Definition: byte_util.hpp:387
constexpr uint16_t le_to_cpu(uint16_t const l) noexcept
Definition: byte_util.hpp:396
lb_endian_t
Simplified reduced endian type only covering little- and big-endian.
Definition: byte_util.hpp:227
std::string to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
constexpr bool is_little_endian(const endian_t byte_order) noexcept
Returns true if given byte_order equals endian::little, otherwise false.
Definition: byte_util.hpp:293
constexpr uint16_t be_to_cpu(uint16_t const n) noexcept
Definition: byte_util.hpp:378
constexpr uint16_t cpu_to_le(uint16_t const h) noexcept
Definition: byte_util.hpp:405
@ 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:53
int_fast32_t snsize_t
Natural 'ssize_t' alternative using int_fast32_t as its natural sized type.
Definition: int_types.hpp:65
static constexpr void bswap_6bytes(uint8_t *sink, const uint8_t *source) noexcept
Definition: eui48.hpp:345
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
bool operator==(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
Definition: callocator.hpp:150
bool operator!=(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
Definition: callocator.hpp:163
STL namespace.
A 48 bit EUI-48 sub-identifier, see EUI48.
Definition: eui48.hpp:51
EUI48Sub & operator=(EUI48Sub &&o) noexcept=default
constexpr EUI48Sub & operator=(const EUI48Sub &o) noexcept=default
jau::nsize_t length
The actual length in bytes of the EUI48 sub-address, less or equal 6 bytes.
Definition: eui48.hpp:68
constexpr EUI48Sub() noexcept
Definition: eui48.hpp:70
bool contains(const EUI48Sub &needle) const noexcept
Returns true, if given EUI48Sub needle is contained in this instance haystack.
Definition: eui48.hpp:173
uint8_t b[6]
The <= 6 byte EUI48 sub-address.
Definition: eui48.hpp:63
constexpr EUI48Sub(const EUI48Sub &o) noexcept=default
static const EUI48Sub ALL_DEVICE
EUI48 MAC address matching all device, i.e.
Definition: eui48.hpp:56
constexpr std::size_t hash_code() const noexcept
Definition: eui48.hpp:115
static const EUI48Sub ANY_DEVICE
EUI48 MAC address matching any device, i.e.
Definition: eui48.hpp:54
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:163
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:129
EUI48Sub(EUI48Sub &&o) noexcept=default
void clear()
Method clears the underlying byte array b and sets length to zero.
Definition: eui48.hpp:127
static const EUI48Sub LOCAL_DEVICE
EUI48 MAC address matching local device, i.e.
Definition: eui48.hpp:58
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:36
static bool scanEUI48Sub(const std::string &str, EUI48Sub &dest, std::string &errmsg)
Fills given EUI48Sub instance via given string representation.
Definition: eui48.cpp:66
A packed 48 bit EUI-48 identifier, formerly known as MAC-48 or simply network device MAC address (Med...
Definition: eui48.hpp:324
uint8_t b[6]
Definition: eui48.hpp:324
std::size_t operator()(jau::EUI48Sub const &a) const noexcept
Definition: eui48.hpp:405
std::size_t operator()(jau::EUI48 const &a) const noexcept
Definition: eui48.hpp:411