jaulib v1.3.6
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
eui48.cpp
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#include <cstring>
27#include <string>
28#include <memory>
29#include <cstdint>
30#include <cstdio>
31
32#include <jau/eui48.hpp>
33#include <jau/secmem.hpp>
34
35using namespace jau;
36
37std::string EUI48Sub::toString() const noexcept {
38 // str_len = 2 * len + ( len - 1 )
39 // str_len = 3 * len - 1
40 // len = ( str_len + 1 ) / 3
41 std::string str;
42 if( 0 < length ) {
43 str.reserve(3 * length - 1);
44
45 if( is_little_endian() ) {
46 for(jau::nsize_t i=0; i < length; ++i) {
47 const jau::nsize_t idx = length - 1 - i;
48 jau::byteHexString(str, b[idx], false /* lowerCase */);
49 if( 0 < idx ) {
50 str.push_back(':');
51 }
52 }
53 } else {
54 for(jau::nsize_t idx=0; idx < length; ++idx) {
55 if( 0 < idx ) {
56 str.push_back(':');
57 }
58 jau::byteHexString(str, b[idx], false /* lowerCase */);
59 }
60 }
61 } else {
62 str.push_back(':');
63 }
64 return str;
65}
66
67bool EUI48Sub::scanEUI48Sub(const std::string& str, EUI48Sub& dest, std::string& errmsg) {
68 const jau::nsize_t str_len = static_cast<jau::nsize_t>( str.length() );
69 dest.clear();
70
71 if( 17 < str_len ) { // not exceeding byte_size
72 errmsg.append("EUI48 sub-string must be less or equal length 17 but "+std::to_string(str_len)+": "+str);
73 return false;
74 }
75 const char * str_ptr = str.c_str();
76 jau::nsize_t j=0;
77 bool exp_colon = false;
78 uint8_t b_[6]; // intermediate result high -> low (big-endian)
79 while( j+1 < str_len /* && byte_count_ < byte_size */ ) { // min 2 chars left
80 const bool is_colon = ':' == str[j];
81 if( exp_colon && !is_colon ) {
82 errmsg.append("EUI48Sub sub-string not in format '01:02:03:0A:0B:0C', but '"+str+"', colon missing, pos "+std::to_string(j)+", len "+std::to_string(str_len));
83 return false;
84 } else if( is_colon ) {
85 ++j;
86 exp_colon = false;
87 } else {
88 if ( sscanf(str_ptr+j, "%02hhx", &b_[dest.length]) != 1 ) // b_: high->low
89 {
90 errmsg.append("EUI48Sub sub-string not in format '01:02:03:0A:0B:0C' but '"+str+"', pos "+std::to_string(j)+", len "+std::to_string(str_len));
91 return false;
92 }
93 j += 2;
94 ++dest.length;
95 exp_colon = true;
96 }
97 }
98 if( is_little_endian() ) {
99 for(j=0; j<dest.length; ++j) { // swap to low->high
100 dest.b[j] = b_[dest.length-1-j];
101 }
102 } else {
103 memcpy(dest.b, b_, dest.length);
104 }
105 return true;
106}
107
108EUI48Sub::EUI48Sub(const std::string& str) {
109 std::string errmsg;
110 if( !scanEUI48Sub(str, *this, errmsg) ) {
112 }
113}
114
115EUI48Sub::EUI48Sub(const uint8_t * b_, const jau::nsize_t len_, const lb_endian_t byte_order) noexcept {
116 length = len_;
117 const jau::nsize_t cpsz = std::max<jau::nsize_t>(sizeof(b), len_);
118 const jau::nsize_t bzsz = sizeof(b) - cpsz;
119
120 if( lb_endian_t::native == byte_order ) {
121 memcpy(b, b_, cpsz);
122 } else {
123 bswap(b, b_, cpsz);
124 }
125 if( bzsz > 0 ) {
126 zero_bytes_sec(b+cpsz, bzsz);
127 }
128}
129
130jau::snsize_t EUI48Sub::indexOf(const uint8_t haystack_b[], const jau::nsize_t haystack_length,
131 const uint8_t needle_b[], const jau::nsize_t needle_length,
132 const lb_endian_t byte_order) noexcept {
133 if( 0 == needle_length ) {
134 return 0;
135 }
136 if( haystack_length < needle_length ) {
137 return -1;
138 }
139 const uint8_t first = needle_b[0];
140 const jau::nsize_t outerEnd = haystack_length - needle_length + 1; // exclusive
141
142 for (jau::nsize_t i = 0; i < outerEnd; i++) {
143 // find first char of other
144 while( haystack_b[i] != first ) {
145 if( ++i == outerEnd ) {
146 return -1;
147 }
148 }
149 if( i < outerEnd ) { // otherLen chars left to match?
150 // continue matching other chars
151 const jau::nsize_t innerEnd = i + needle_length; // exclusive
152 jau::nsize_t j = i, k=0;
153 do {
154 if( ++j == innerEnd ) {
155 // gotcha
156 if( lb_endian_t::native == byte_order ) {
157 return static_cast<jau::snsize_t>(i);
158 } else {
159 return static_cast<jau::snsize_t>(5 - i - ( needle_length - 1 ));
160 }
161 }
162 } while( haystack_b[j] == needle_b[++k] );
163 }
164 }
165 return -1;
166}
167
168std::string EUI48::toString() const noexcept {
169 // str_len = 2 * len + ( len - 1 )
170 // str_len = 3 * len - 1
171 // len = ( str_len + 1 ) / 3
172 std::string str;
173 str.reserve(17); // 6 * 2 + ( 6 - 1 )
174
175 if( is_little_endian() ) {
176 jau::byteHexString(str, b[5], false /* lowerCase */);
177 str.push_back(':');
178 jau::byteHexString(str, b[4], false /* lowerCase */);
179 str.push_back(':');
180 jau::byteHexString(str, b[3], false /* lowerCase */);
181 str.push_back(':');
182 jau::byteHexString(str, b[2], false /* lowerCase */);
183 str.push_back(':');
184 jau::byteHexString(str, b[1], false /* lowerCase */);
185 str.push_back(':');
186 jau::byteHexString(str, b[0], false /* lowerCase */);
187 } else {
188 jau::byteHexString(str, b[0], false /* lowerCase */);
189 str.push_back(':');
190 jau::byteHexString(str, b[1], false /* lowerCase */);
191 str.push_back(':');
192 jau::byteHexString(str, b[2], false /* lowerCase */);
193 str.push_back(':');
194 jau::byteHexString(str, b[3], false /* lowerCase */);
195 str.push_back(':');
196 jau::byteHexString(str, b[4], false /* lowerCase */);
197 str.push_back(':');
198 jau::byteHexString(str, b[5], false /* lowerCase */);
199 }
200 return str;
201}
202
203bool EUI48::scanEUI48(const std::string& str, EUI48& dest, std::string& errmsg) {
204 if( 17 != str.length() ) {
205 errmsg.append("EUI48 string not of length 17 but ");
206 errmsg.append(std::to_string(str.length()));
207 errmsg.append(": "+str);
208 return false;
209 }
210 int scanres;
211 if( is_little_endian() ) {
212 scanres = sscanf(str.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
213 &dest.b[5], &dest.b[4], &dest.b[3], &dest.b[2], &dest.b[1], &dest.b[0]);
214 } else {
215 scanres = sscanf(str.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
216 &dest.b[0], &dest.b[1], &dest.b[2], &dest.b[3], &dest.b[4], &dest.b[5]);
217 }
218 if ( 6 != scanres ) {
219 errmsg.append("EUI48 string not in format '01:02:03:0A:0B:0C' but '"+str+"'");
220 return false;
221 }
222 // sscanf provided host data type, in which we store the values,
223 // hence no endian conversion
224 return true;
225}
226
227EUI48::EUI48(const std::string& str) {
228 std::string errmsg;
229 if( !scanEUI48(str, *this, errmsg) ) {
231 }
232}
233
234EUI48::EUI48(const uint8_t * source, const lb_endian_t byte_order) noexcept {
235 if( lb_endian_t::native == byte_order ) {
236 memcpy(b, source, sizeof(b));
237 } else {
238 bswap_6bytes(b, source);
239 }
240}
241
242jau::nsize_t EUI48::put(uint8_t * const sink, const lb_endian_t byte_order) const noexcept {
243 if( lb_endian_t::native == byte_order ) {
244 memcpy(sink, b, sizeof(b));
245 } else {
246 bswap_6bytes(sink, b);
247 }
248 return 6;
249}
250
251static uint8_t _EUI48_ALL_DEVICE[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
252static uint8_t _EUI48_LOCAL_DEVICE[] = {0x00, 0x00, 0x00, 0xff, 0xff, 0xff};
253
254const EUI48Sub jau::EUI48Sub::ANY_DEVICE; // default ctor is zero bytes!
257
258const EUI48 jau::EUI48::ANY_DEVICE; // default ctor is zero bytes!
261
#define E_FILE_LINE
static uint8_t _EUI48_LOCAL_DEVICE[]
Definition eui48.cpp:252
static uint8_t _EUI48_ALL_DEVICE[]
Definition eui48.cpp:251
constexpr bool is_little_endian() noexcept
Evaluates true if platform is running in little endian mode, i.e.
constexpr uint16_t bswap(uint16_t const source) noexcept
Definition byte_util.hpp:86
lb_endian_t
Simplified reduced endian type only covering little- and big-endian.
@ native
Identifier for native platform type, one of the above.
@ little
Identifier for little endian, equivalent to endian::little.
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
static constexpr void bswap_6bytes(uint8_t *sink, const uint8_t *source) noexcept
Definition eui48.hpp:345
void zero_bytes_sec(void *s, size_t n) noexcept __attrdecl_no_optimize__
Wrapper to ::explicit_bzero(), ::bzero() or ::memset(), whichever is available in that order.
std::string & byteHexString(std::string &dest, const uint8_t value, const bool lowerCase) noexcept
Produce a hexadecimal string representation of the given byte value.
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
A 48 bit EUI-48 sub-identifier, see EUI48.
Definition eui48.hpp:51
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
uint8_t b[6]
The <= 6 byte EUI48 sub-address.
Definition eui48.hpp:63
static const EUI48Sub ALL_DEVICE
EUI48 MAC address matching all device, i.e.
Definition eui48.hpp:56
static const EUI48Sub ANY_DEVICE
EUI48 MAC address matching any device, i.e.
Definition eui48.hpp:54
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:130
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:37
static bool scanEUI48Sub(const std::string &str, EUI48Sub &dest, std::string &errmsg)
Fills given EUI48Sub instance via given string representation.
Definition eui48.cpp:67
A packed 48 bit EUI-48 identifier, formerly known as MAC-48 or simply network device MAC address (Med...
Definition eui48.hpp:324
static const EUI48 LOCAL_DEVICE
EUI48 MAC address matching local device, i.e.
Definition eui48.hpp:324
uint8_t b[6]
Definition eui48.hpp:324
static const EUI48 ANY_DEVICE
EUI48 MAC address matching any device, i.e.
Definition eui48.hpp:324
static const EUI48 ALL_DEVICE
EUI48 MAC address matching all device, i.e.
Definition eui48.hpp:324
static bool scanEUI48(const std::string &str, EUI48 &dest, std::string &errmsg)
Definition eui48.cpp:203
jau::nsize_t put(uint8_t *const sink, const lb_endian_t byte_order) const noexcept
Definition eui48.cpp:242
constexpr EUI48() noexcept
Definition eui48.hpp:324
std::string toString() const noexcept
Definition eui48.cpp:168