jaulib v1.4.0-2-g788cf73
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 <cstdint>
29#include <cstdio>
30
31#include <jau/secmem.hpp>
32#include <jau/string_util.hpp>
33#include <jau/byte_util.hpp>
34#include <jau/io/eui48.hpp>
35
36using namespace jau;
37using namespace jau::io::net;
38
39std::string EUI48Sub::toString() const noexcept {
40 // str_len = 2 * len + ( len - 1 )
41 // str_len = 3 * len - 1
42 // len = ( str_len + 1 ) / 3
43 std::string str;
44 if( 0 < length ) {
45 str.reserve(3 * length - 1);
46
47 if( is_little_endian() ) {
48 for(jau::nsize_t i=0; i < length; ++i) {
49 const jau::nsize_t idx = length - 1 - i;
51 if( 0 < idx ) {
52 str.push_back(':');
53 }
54 }
55 } else {
56 for(jau::nsize_t idx=0; idx < length; ++idx) {
57 if( 0 < idx ) {
58 str.push_back(':');
59 }
61 }
62 }
63 } else {
64 str.push_back(':');
65 }
66 return str;
67}
68
69bool EUI48Sub::scanEUI48Sub(const std::string& str, EUI48Sub& dest, std::string& errmsg) {
70 const jau::nsize_t str_len = static_cast<jau::nsize_t>( str.length() );
71 dest.clear();
72
73 if( 17 < str_len ) { // not exceeding byte_size
74 errmsg.append("EUI48 sub-string must be less or equal length 17 but "+std::to_string(str_len)+": "+str);
75 return false;
76 }
77 const char * str_ptr = str.c_str();
78 jau::nsize_t j=0;
79 bool exp_colon = false;
80 uint8_t b_[6]; // intermediate result high -> low (big-endian)
81 while( j+1 < str_len /* && byte_count_ < byte_size */ ) { // min 2 chars left
82 const bool is_colon = ':' == str[j];
83 if( exp_colon && !is_colon ) {
84 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));
85 return false;
86 } else if( is_colon ) {
87 ++j;
88 exp_colon = false;
89 } else {
90 if ( sscanf(str_ptr+j, "%02hhx", &b_[dest.length]) != 1 ) // b_: high->low
91 {
92 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));
93 return false;
94 }
95 j += 2;
96 ++dest.length;
97 exp_colon = true;
98 }
99 }
100 if( is_little_endian() ) {
101 for(j=0; j<dest.length; ++j) { // swap to low->high
102 dest.b[j] = b_[dest.length-1-j];
103 }
104 } else {
105 memcpy(dest.b, b_, dest.length);
106 }
107 return true;
108}
109
110EUI48Sub::EUI48Sub(const std::string& str) {
111 std::string errmsg;
112 if( !scanEUI48Sub(str, *this, errmsg) ) {
114 }
115}
116
117EUI48Sub::EUI48Sub(const uint8_t * b_, const jau::nsize_t len_, const lb_endian_t byte_order) noexcept {
118 length = len_;
119 const jau::nsize_t cpsz = std::max<jau::nsize_t>(sizeof(b), len_);
120 const jau::nsize_t bzsz = sizeof(b) - cpsz;
121
122 if( lb_endian_t::native == byte_order ) {
123 std::memcpy(b, b_, cpsz);
124 } else {
125 jau::bswap(b, b_, cpsz);
126 }
127 if( bzsz > 0 ) {
128 zero_bytes_sec(b+cpsz, bzsz);
129 }
130}
131
132jau::snsize_t EUI48Sub::indexOf(const uint8_t haystack_b[], const jau::nsize_t haystack_length,
133 const uint8_t needle_b[], const jau::nsize_t needle_length,
134 const lb_endian_t byte_order) noexcept {
135 if( 0 == needle_length ) {
136 return 0;
137 }
138 if( haystack_length < needle_length ) {
139 return -1;
140 }
141 const uint8_t first = needle_b[0];
142 const jau::nsize_t outerEnd = haystack_length - needle_length + 1; // exclusive
143
144 for (jau::nsize_t i = 0; i < outerEnd; i++) {
145 // find first char of other
146 while( haystack_b[i] != first ) {
147 if( ++i == outerEnd ) {
148 return -1;
149 }
150 }
151 if( i < outerEnd ) { // otherLen chars left to match?
152 // continue matching other chars
153 const jau::nsize_t innerEnd = i + needle_length; // exclusive
154 jau::nsize_t j = i, k=0;
155 do {
156 if( ++j == innerEnd ) {
157 // gotcha
158 if( lb_endian_t::native == byte_order ) {
159 return static_cast<jau::snsize_t>(i);
160 } else {
161 return static_cast<jau::snsize_t>(5 - i - ( needle_length - 1 ));
162 }
163 }
164 } while( haystack_b[j] == needle_b[++k] );
165 }
166 }
167 return -1;
168}
169
170std::string EUI48::toString() const noexcept {
171 // str_len = 2 * len + ( len - 1 )
172 // str_len = 3 * len - 1
173 // len = ( str_len + 1 ) / 3
174 std::string str;
175 str.reserve(17); // 6 * 2 + ( 6 - 1 )
176
177 if( is_little_endian() ) {
179 str.push_back(':');
181 str.push_back(':');
183 str.push_back(':');
185 str.push_back(':');
187 str.push_back(':');
189 } else {
191 str.push_back(':');
193 str.push_back(':');
195 str.push_back(':');
197 str.push_back(':');
199 str.push_back(':');
201 }
202 return str;
203}
204
205bool EUI48::scanEUI48(const std::string& str, EUI48& dest, std::string& errmsg) {
206 if( 17 != str.length() ) {
207 errmsg.append("EUI48 string not of length 17 but ");
208 errmsg.append(std::to_string(str.length()));
209 errmsg.append(": "+str);
210 return false;
211 }
212 int scanres;
213 if( is_little_endian() ) {
214 scanres = sscanf(str.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
215 &dest.b[5], &dest.b[4], &dest.b[3], &dest.b[2], &dest.b[1], &dest.b[0]);
216 } else {
217 scanres = sscanf(str.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
218 &dest.b[0], &dest.b[1], &dest.b[2], &dest.b[3], &dest.b[4], &dest.b[5]);
219 }
220 if ( 6 != scanres ) {
221 errmsg.append("EUI48 string not in format '01:02:03:0A:0B:0C' but '"+str+"'");
222 return false;
223 }
224 // sscanf provided host data type, in which we store the values,
225 // hence no endian conversion
226 return true;
227}
228
229EUI48::EUI48(const std::string& str) {
230 std::string errmsg;
231 if( !scanEUI48(str, *this, errmsg) ) {
233 }
234}
235
236EUI48::EUI48(const uint8_t * source, const lb_endian_t byte_order) noexcept {
237 if( lb_endian_t::native == byte_order ) {
238 memcpy(b, source, sizeof(b));
239 } else {
240 bswap_6bytes(b, source);
241 }
242}
243
244jau::nsize_t EUI48::put(uint8_t * const sink, const lb_endian_t byte_order) const noexcept {
245 if( lb_endian_t::native == byte_order ) {
246 memcpy(sink, b, sizeof(b));
247 } else {
248 bswap_6bytes(sink, b);
249 }
250 return 6;
251}
252
253static uint8_t _EUI48_ALL_DEVICE[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
254static uint8_t _EUI48_LOCAL_DEVICE[] = {0x00, 0x00, 0x00, 0xff, 0xff, 0xff};
255
256const EUI48Sub jau::io::net::EUI48Sub::ANY_DEVICE; // default ctor is zero bytes!
259
260const EUI48 jau::io::net::EUI48::ANY_DEVICE; // default ctor is zero bytes!
263
#define E_FILE_LINE
static uint8_t _EUI48_LOCAL_DEVICE[]
Definition eui48.cpp:254
static uint8_t _EUI48_ALL_DEVICE[]
Definition eui48.cpp:253
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:88
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:343
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 & appendToHexString(std::string &dest, const uint8_t value, const LoUpCase capitalization=LoUpCase::lower) noexcept
Produce a hexadecimal string representation of the given byte value and appends it to the given strin...
__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:49
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
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
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
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
static const EUI48 LOCAL_DEVICE
EUI48 MAC address matching local device, i.e.
Definition eui48.hpp:322
constexpr EUI48() noexcept
Definition eui48.hpp:322
static bool scanEUI48(const std::string &str, EUI48 &dest, std::string &errmsg)
Definition eui48.cpp:205
static const EUI48 ANY_DEVICE
EUI48 MAC address matching any device, i.e.
Definition eui48.hpp:322
jau::nsize_t put(uint8_t *const sink, const lb_endian_t byte_order) const noexcept
Definition eui48.cpp:244
std::string toString() const noexcept
Definition eui48.cpp:170
static const EUI48 ALL_DEVICE
EUI48 MAC address matching all device, i.e.
Definition eui48.hpp:322