Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter

- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
This commit is contained in:
Eric F
2026-06-08 00:38:27 -04:00
parent 468cfeaa50
commit d398a6ced2
7326 changed files with 1177561 additions and 7 deletions

View File

@@ -0,0 +1,377 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
#include "everest/io/mdns/mdns.hpp"
#include <arpa/inet.h>
#include <cstring>
#include <iostream>
namespace everest::lib::io::mdns {
namespace {
std::string parse_name(const std::uint8_t* buffer, int size, int* offset) {
std::string name = "";
int curr = *offset;
bool moved = false;
int next_offset = -1;
while (curr < size && buffer[curr] != 0) {
if ((buffer[curr] & 0xC0) == 0xC0) {
int pointer_offset = ((buffer[curr] & 0x3F) << 8) | buffer[curr + 1];
if (!moved) {
next_offset = curr + 2;
}
curr = pointer_offset;
moved = true;
} else {
int len = buffer[curr];
curr++;
for (int i = 0; i < len && curr < size; ++i) {
name += static_cast<char>(buffer[curr]);
curr++;
}
if (curr < size && buffer[curr] != 0) {
name += ".";
}
}
}
*offset = moved ? next_offset : curr + 1;
return name;
}
void parse_mdns_A(const std::uint8_t* buffer, mDNS_discovery& mdns) {
auto size_of_ip_string = 16;
mdns.ip.resize(size_of_ip_string);
std::snprintf(mdns.ip.data(), mdns.ip.size(), "%d.%d.%d.%d", buffer[0], buffer[1], buffer[2], buffer[3]);
}
void parse_mdns_SRV(const std::uint8_t* base, int record_data_offset, mDNS_discovery& mdns, int size) {
mdns.port = (base[record_data_offset + 4] << 8) | base[record_data_offset + 5];
int name_offset = record_data_offset + 6;
mdns.hostname = parse_name(base, size, &name_offset);
}
void parse_mdns_TXT(const std::uint8_t* buffer, mDNS_discovery& mdns, int rdlen) {
int txt_ptr = 0;
int end_of_record = rdlen;
while (txt_ptr < end_of_record) {
std::uint8_t txt_len = buffer[txt_ptr];
txt_ptr++;
if (txt_ptr + txt_len <= end_of_record) {
const char* entry_cstr = reinterpret_cast<const char*>(&buffer[txt_ptr]);
std::string entry(entry_cstr, txt_len);
std::size_t sep = entry.find('=');
if (sep != std::string::npos) {
std::string key = entry.substr(0, sep);
std::string val = entry.substr(sep + 1);
mdns.add_string(key, val);
}
txt_ptr += txt_len;
} else {
break;
}
}
}
void parse_mdns_PTR(const std::uint8_t* base, int record_data_offset, mDNS_discovery& mdns, int size) {
std::string service_instance = parse_name(base, size, &record_data_offset);
mdns.service_instance = service_instance;
}
void encode_dns_name(std::vector<std::uint8_t>& packet, std::string const& name) {
std::size_t start = 0;
std::size_t end;
while ((end = name.find('.', start)) != std::string::npos) {
auto label_len = end - start;
if (label_len > 63) {
label_len = 63;
}
packet.push_back(static_cast<std::uint8_t>(label_len));
for (std::size_t i = start; i < start + label_len; ++i) {
packet.push_back(static_cast<std::uint8_t>(name[i]));
}
start = end + 1;
}
if (start < name.length()) {
auto label_len = name.length() - start;
if (label_len > 63) {
label_len = 63;
}
packet.push_back(static_cast<std::uint8_t>(label_len));
for (std::size_t i = start; i < start + label_len; ++i) {
packet.push_back(static_cast<std::uint8_t>(name[i]));
}
}
packet.push_back(0);
}
void append_uint16(std::vector<std::uint8_t>& packet, std::uint16_t value) {
packet.push_back(static_cast<std::uint8_t>((value >> 8) & 0xFF));
packet.push_back(static_cast<std::uint8_t>(value & 0xFF));
}
void append_uint32(std::vector<std::uint8_t>& packet, std::uint32_t value) {
packet.push_back(static_cast<std::uint8_t>((value >> 24) & 0xFF));
packet.push_back(static_cast<std::uint8_t>((value >> 16) & 0xFF));
packet.push_back(static_cast<std::uint8_t>((value >> 8) & 0xFF));
packet.push_back(static_cast<std::uint8_t>(value & 0xFF));
}
} // namespace
[[maybe_unused]] std::optional<mDNS_discovery> parse_mdns_packet(std::vector<std::uint8_t> const& packet) {
int size = packet.size();
const auto* buf = packet.data();
auto const mdns_packet_min_size = 12;
if (size < mdns_packet_min_size) {
return std::nullopt;
}
if ((buf[2] & 0x80) == 0) {
return std::nullopt;
}
mDNS_discovery result;
std::size_t questions = (buf[4] << 8) | buf[5];
std::size_t answers = (buf[6] << 8) | buf[7];
std::size_t authority = (buf[8] << 8) | buf[9];
std::size_t additional = (buf[10] << 8) | buf[11];
int curr = mdns_packet_min_size;
for (size_t i = 0; i < questions && curr < size; ++i) {
parse_name(buf, size, &curr);
curr += 4;
}
auto const mdns_record_header_size = 10;
int total_records = static_cast<int>(answers + authority + additional);
for (int i = 0; i < total_records && curr < size; ++i) {
std::string name = parse_name(buf, size, &curr);
if (curr + mdns_record_header_size > size) {
break;
}
std::uint16_t type = (buf[curr] << 8) | buf[curr + 1];
std::uint16_t rdlen = (buf[curr + 8] << 8) | buf[curr + 9];
curr += mdns_record_header_size;
if (type == 0x01 && rdlen == 4) {
parse_mdns_A(buf + curr, result);
} else if (type == 0x21) {
parse_mdns_SRV(buf, curr, result, size);
} else if (type == 0x10) {
parse_mdns_TXT(buf + curr, result, rdlen);
} else if (type == 0x0C) {
parse_mdns_PTR(buf, curr, result, size);
}
curr += rdlen;
}
return result;
}
[[maybe_unused]] std::vector<std::uint8_t> create_mdns_query(std::string const& name) {
std::vector<uint8_t> encoded;
std::size_t start = 0, end;
while ((end = name.find('.', start)) != std::string::npos) {
encoded.push_back(static_cast<uint8_t>(end - start));
for (std::size_t i = start; i < end; ++i) {
encoded.push_back(name[i]);
}
start = end + 1;
}
encoded.push_back(static_cast<uint8_t>(name.length() - start));
for (std::size_t i = start; i < name.length(); ++i) {
encoded.push_back(name[i]);
}
encoded.push_back(0);
std::vector<std::uint8_t> packet = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
#if defined(__GNUC__) && (__GNUC__ < 12)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overread"
#endif
packet.insert(packet.end(), encoded.begin(), encoded.end());
#if defined(__GNUC__) && (__GNUC__ < 12)
#pragma GCC diagnostic pop
#endif
packet.push_back(0x00);
packet.push_back(0x0c);
packet.push_back(0x00);
packet.push_back(0x01);
return packet;
}
bool apply_value(std::string const& src, std::string& tar) {
if (src == tar) {
return false;
}
if (src.empty()) {
return false;
}
tar = src;
return true;
}
bool apply_value(std::uint16_t const src, std::uint16_t& tar) {
if (src == 0 or src == tar) {
return false;
}
tar = src;
return true;
}
bool mDNS_registry::update(const mDNS_discovery& update) {
if (update.service_instance.empty()) {
return false;
}
bool something_new = data.count(update.service_instance) == 0;
auto& item = data[update.service_instance];
item.service_instance = update.service_instance;
something_new = apply_value(update.port, item.port) || something_new;
something_new = apply_value(update.hostname, item.hostname) || something_new;
something_new = apply_value(update.ip, item.ip) || something_new;
for (auto const& [key, val] : update.txt) {
something_new = apply_value(val, item.txt[key]) || something_new;
}
return something_new;
}
void mDNS_registry::remove(const std::string& instance) {
data.erase(instance);
}
void mDNS_registry::clear() {
data.clear();
}
mDNS_registry::registry const& mDNS_registry::get() {
return data;
}
[[maybe_unused]] std::vector<std::uint8_t> create_mdns_response(mDNS_discovery const& service,
std::string const& service_type) {
std::string service_fqdn = service_type + ".local";
std::string instance_fqdn = service.service_instance;
if (instance_fqdn.empty()) {
instance_fqdn = service.hostname + "." + service_fqdn;
}
std::string host_fqdn = service.hostname + ".local";
std::vector<std::uint8_t> packet;
append_uint16(packet, 0x0000); // Transaction ID
append_uint16(packet, 0x8400); // Flags: response, authoritative
append_uint16(packet, 0x0000); // Questions
append_uint16(packet, 0x0004); // Answer RRs (PTR + SRV + TXT + A)
append_uint16(packet, 0x0000); // Authority RRs
append_uint16(packet, 0x0000); // Additional RRs
auto const default_ttl = static_cast<std::uint32_t>(120);
// PTR record: service_type.local -> instance_fqdn
encode_dns_name(packet, service_fqdn);
append_uint16(packet, 0x000C);
append_uint16(packet, 0x0001);
append_uint32(packet, default_ttl);
std::vector<std::uint8_t> ptr_rdata;
encode_dns_name(ptr_rdata, instance_fqdn);
append_uint16(packet, static_cast<std::uint16_t>(ptr_rdata.size()));
packet.insert(packet.end(), ptr_rdata.begin(), ptr_rdata.end());
// SRV record: instance_fqdn -> host:port
encode_dns_name(packet, instance_fqdn);
append_uint16(packet, 0x0021);
append_uint16(packet, 0x8001);
append_uint32(packet, default_ttl);
std::vector<std::uint8_t> srv_rdata;
append_uint16(srv_rdata, 0x0000); // Priority
append_uint16(srv_rdata, 0x0000); // Weight
append_uint16(srv_rdata, service.port);
encode_dns_name(srv_rdata, host_fqdn);
append_uint16(packet, static_cast<std::uint16_t>(srv_rdata.size()));
packet.insert(packet.end(), srv_rdata.begin(), srv_rdata.end());
// TXT record: instance_fqdn -> key=value pairs
encode_dns_name(packet, instance_fqdn);
append_uint16(packet, 0x0010);
append_uint16(packet, 0x8001);
append_uint32(packet, default_ttl);
std::vector<std::uint8_t> txt_rdata;
for (auto const& [key, val] : service.txt) {
std::string entry = key + "=" + val;
txt_rdata.push_back(static_cast<std::uint8_t>(entry.size()));
for (char ch : entry) {
txt_rdata.push_back(static_cast<std::uint8_t>(ch));
}
}
if (txt_rdata.empty()) {
txt_rdata.push_back(0);
}
append_uint16(packet, static_cast<std::uint16_t>(txt_rdata.size()));
packet.insert(packet.end(), txt_rdata.begin(), txt_rdata.end());
// A record: host_fqdn -> IP
encode_dns_name(packet, host_fqdn);
append_uint16(packet, 0x0001);
append_uint16(packet, 0x8001);
append_uint32(packet, default_ttl);
append_uint16(packet, 0x0004);
struct in_addr addr;
if (inet_pton(AF_INET, service.ip.c_str(), &addr) == 1) {
auto* bytes = reinterpret_cast<std::uint8_t*>(&addr.s_addr);
packet.push_back(bytes[0]);
packet.push_back(bytes[1]);
packet.push_back(bytes[2]);
packet.push_back(bytes[3]);
} else {
packet.push_back(0);
packet.push_back(0);
packet.push_back(0);
packet.push_back(0);
}
return packet;
}
[[maybe_unused]] bool is_query_for(std::vector<std::uint8_t> const& packet, std::string const& service_type) {
int size = static_cast<int>(packet.size());
auto const* buf = packet.data();
auto const mdns_packet_min_size = 12;
if (size < mdns_packet_min_size) {
return false;
}
if ((buf[2] & 0x80) != 0) {
return false;
}
std::size_t questions = (buf[4] << 8) | buf[5];
if (questions == 0) {
return false;
}
int curr = mdns_packet_min_size;
std::string service_fqdn = service_type + ".local";
for (std::size_t i = 0; i < questions && curr < size; ++i) {
std::string qname = parse_name(buf, size, &curr);
if (curr + 4 > size) {
break;
}
std::uint16_t qtype = (buf[curr] << 8) | buf[curr + 1];
curr += 4;
if ((qtype == 0x0C || qtype == 0xFF) && qname == service_fqdn) {
return true;
}
}
return false;
}
} // namespace everest::lib::io::mdns

View File

@@ -0,0 +1,66 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
#include "everest/io/udp/udp_payload.hpp"
#include "everest/io/udp/udp_socket.hpp"
#include <arpa/inet.h>
#include <everest/io/event/fd_event_handler.hpp>
#include <everest/io/event/unique_fd.hpp>
#include <everest/io/mdns/mdns.hpp>
#include <everest/io/mdns/mdns_socket.hpp>
#include <everest/io/socket/socket.hpp>
#include <iostream>
#include <net/if.h>
#include <netinet/in.h>
#include <optional>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
namespace everest::lib::io::mdns {
/////////////////////////////////////////////////
bool mdns_socket::open(std::string const& interface) {
auto const mdns_port = 5353;
auto const* const mdns_ip = "224.0.0.251";
auto socket = socket::open_mdns_socket(interface);
m_owned_udp_fd = std::move(socket);
target.addr = inet_addr(mdns_ip);
target.port = htons(mdns_port);
target.family = AF_INET;
return socket::get_pending_error(m_owned_udp_fd) == 0;
}
bool mdns_socket::tx(PayloadT const& payload) {
return tx_impl(payload.buffer.data(), payload.size(), target);
}
bool mdns_socket::rx(PayloadT& payload) {
ssize_t msg_size = 0;
auto result = rx_impl(rx_buffer.data(), rx_buffer.size(), msg_size);
if (result) {
payload.set_message(rx_buffer.data(), msg_size);
}
return result.has_value();
}
bool mdns_socket::query(std::string const& what) {
PayloadT payload;
payload.buffer = everest::lib::io::mdns::create_mdns_query(what);
return tx(payload);
}
bool mdns_socket::announce(mDNS_discovery const& service, std::string const& service_type) {
PayloadT payload;
payload.buffer = create_mdns_response(service, service_type);
return tx(payload);
}
} // namespace everest::lib::io::mdns