123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- #include "kbf/net.h"
- #include <sstream>
- #include <iomanip>
- #include <arpa/inet.h>
- #include <regex>
- #include <esp_system.h>
- #include <esp_log.h>
- #include "kbf/macros.h"
- using std::string;
- using namespace kbf;
- string net::MAC::str() const {
- using std::setw;
- std::stringstream ss;
- ss << std::hex << std::setfill('0') << setw(2) << std::right << std::uppercase
- << (uint32_t) this->addr[0] << ":" << setw(2)
- << (uint32_t) this->addr[1] << ":" << setw(2)
- << (uint32_t) this->addr[2] << ":" << setw(2)
- << (uint32_t) this->addr[3] << ":" << setw(2)
- << (uint32_t) this->addr[4] << ":" << setw(2)
- << (uint32_t) this->addr[5];
- return ss.str();
- }
- net::MAC::MAC(const uint8_t addr[6]) {
- // TODO look up some (syntax) magic for array initialization
- for (int i = 0; i < 6; i++) {
- this->addr[i] = addr[i];
- }
- }
- void net::setMac(const MAC &mac) {
- ESP_LOGI(TAG, "setting base MAC address to %s", mac.str().c_str());
- CHECK(esp_base_mac_addr_set(mac.addr));
- }
- net::MAC net::getMac() {
- uint8_t addr[6]{};
- CHECK(esp_base_mac_addr_get(addr));
- auto mac = MAC(addr);
- ESP_LOGI(TAG, "read base MAC address: %s", mac.str().c_str());
- return mac;
- }
- string net::IP::str() const {
- if (valid) return inet_ntoa(addr);
- else return "";
- }
- net::IP::IP(const std::string &address) {
- addr = 0;
- std::regex regex(R"(^(\d+).(\d+).(\d+).(\d+)$)");
- std::smatch submatch;
- if (std::regex_match(address, submatch, regex)) {
- valid = true;
- } else {
- invalidate(address);
- return;
- }
- for (int i = 1; i <= 4; i++) {
- ESP_LOGD(TAG, "submatch[%d] = %s", i, submatch[i].str().c_str());
- int byte = std::stoi(submatch[i].str());
- if (byte < 0 || byte > 255) {
- invalidate(address);
- return;
- }
- addr += byte << (i - 1) * 8;
- }
- }
- void net::IP::invalidate(const string &address) {
- ESP_LOGW(TAG, "invalid IP address: \"%s\"", address.c_str());
- valid = false;
- }
- net::MDNS::MDNS(const std::string &hostname) {
- ESP_LOGI(TAG, "MDNS(\"%s\")", hostname.c_str());
- CHECK(mdns_init());
- CHECK(mdns_instance_name_set(INSTANCE_NAME));
- if (!hostname.empty()) {
- setHostname(hostname);
- }
- }
- net::MDNS::~MDNS() {
- ESP_LOGI(TAG, "~MDNS()");
- mdns_free();
- }
- void net::MDNS::setHostname(const std::string& hostname) {
- ESP_LOGI(TAG, "setHostname(\"%s\")", hostname.c_str());
- CHECK(mdns_hostname_set(hostname.c_str()));
- }
- net::IP *net::MDNS::queryA(const std::string &hostname, int timeoutMs) {
- ESP_LOGI(TAG, "queryA(\"%s\")", hostname.c_str());
- struct esp_ip4_addr addr{};
- addr.addr = 0;
- esp_err_t err = mdns_query_a(hostname.c_str(), timeoutMs, &addr);
- if (err == ESP_OK) {
- auto ip = new net::IP(addr);
- ESP_LOGI(TAG, " query A: %s", ip->str().c_str());
- return ip;
- } else if (err == ESP_ERR_NOT_FOUND) {
- ESP_LOGI(TAG, " query A: hostname not found");
- return nullptr;
- }
- CHECK(err);
- return nullptr; // unreachable
- }
- void
- net::MDNS::addService(const string &serviceType, int port, const string &instanceName, const net::Proto &proto) {
- ESP_LOGI(TAG, "addService(%s, %d, %s, %s)", serviceType.c_str(), port, instanceName.c_str(), protoStr(proto));
- mdns_service_add(instanceName == "" ? nullptr : instanceName.c_str(), serviceType.c_str(), protoStr(proto), port,
- nullptr, 0);
- }
- std::vector<net::MDNS::PTRResult> net::MDNS::queryPTR(const string &serviceType, int timeoutMs, net::Proto proto) {
- ESP_LOGI(TAG, "queryPTR(%s, %s, %d)", serviceType.c_str(), protoStr(proto), timeoutMs);
- std::vector<PTRResult> ret;
- mdns_result_t *result = nullptr;
- CHECK(mdns_query_ptr(serviceType.c_str(), protoStr(proto), timeoutMs, 20, &result));
- for (; result; result = result->next) {
- PTRResult tmp{
- // .interface = static_cast<Interface>(result->tcpip_if),
- // .ipVersion = static_cast<IPVersion>(result->ip_protocol),
- .protocol = proto,
- .port = result->port,
- .instanceName = result->instance_name,
- .hostName = result->hostname,
- };
- auto addr = result->addr;
- for (; addr; addr = addr->next) {
- if (addr->addr.type == IPADDR_TYPE_V6) {
- ESP_LOGW(TAG, "IPv6 support not implemented");
- continue;
- }
- tmp.addresses.push_back(IP(addr->addr.u_addr.ip4));
- }
- ESP_LOGI(TAG, " result: %s on %s", tmp.instanceName.c_str(), tmp.hostName.c_str());
- ret.push_back(tmp);
- }
- return ret;
- }
- const char *net::MDNS::protoStr(net::Proto proto) {
- return proto == Proto::TCP ? "_tcp" : "_udp";
- }
|