net.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #include "kbf/net.h"
  2. #include <sstream>
  3. #include <iomanip>
  4. #include <arpa/inet.h>
  5. #include <regex>
  6. #include <esp_system.h>
  7. #include <esp_log.h>
  8. #include "kbf/macros.h"
  9. using std::string;
  10. using namespace kbf;
  11. string net::MAC::str() const {
  12. using std::setw;
  13. std::stringstream ss;
  14. ss << std::hex << std::setfill('0') << setw(2) << std::right << std::uppercase
  15. << (uint32_t) this->addr[0] << ":" << setw(2)
  16. << (uint32_t) this->addr[1] << ":" << setw(2)
  17. << (uint32_t) this->addr[2] << ":" << setw(2)
  18. << (uint32_t) this->addr[3] << ":" << setw(2)
  19. << (uint32_t) this->addr[4] << ":" << setw(2)
  20. << (uint32_t) this->addr[5];
  21. return ss.str();
  22. }
  23. net::MAC::MAC(const uint8_t addr[6]) {
  24. // TODO look up some (syntax) magic for array initialization
  25. for (int i = 0; i < 6; i++) {
  26. this->addr[i] = addr[i];
  27. }
  28. }
  29. void net::setMac(const MAC &mac) {
  30. ESP_LOGI(TAG, "setting base MAC address to %s", mac.str().c_str());
  31. CHECK(esp_base_mac_addr_set(mac.addr));
  32. }
  33. net::MAC net::getMac() {
  34. uint8_t addr[6]{};
  35. CHECK(esp_base_mac_addr_get(addr));
  36. auto mac = MAC(addr);
  37. ESP_LOGI(TAG, "read base MAC address: %s", mac.str().c_str());
  38. return mac;
  39. }
  40. string net::IP::str() const {
  41. if (valid) return inet_ntoa(addr);
  42. else return "";
  43. }
  44. net::IP::IP(const std::string &address) {
  45. addr = 0;
  46. std::regex regex(R"(^(\d+).(\d+).(\d+).(\d+)$)");
  47. std::smatch submatch;
  48. if (std::regex_match(address, submatch, regex)) {
  49. valid = true;
  50. } else {
  51. invalidate(address);
  52. return;
  53. }
  54. for (int i = 1; i <= 4; i++) {
  55. ESP_LOGD(TAG, "submatch[%d] = %s", i, submatch[i].str().c_str());
  56. int byte = std::stoi(submatch[i].str());
  57. if (byte < 0 || byte > 255) {
  58. invalidate(address);
  59. return;
  60. }
  61. addr += byte << (i - 1) * 8;
  62. }
  63. }
  64. void net::IP::invalidate(const string &address) {
  65. ESP_LOGW(TAG, "invalid IP address: \"%s\"", address.c_str());
  66. valid = false;
  67. }
  68. net::MDNS::MDNS(const std::string &hostname) {
  69. ESP_LOGI(TAG, "MDNS(\"%s\")", hostname.c_str());
  70. CHECK(mdns_init());
  71. CHECK(mdns_instance_name_set(INSTANCE_NAME));
  72. if (!hostname.empty()) {
  73. setHostname(hostname);
  74. }
  75. }
  76. net::MDNS::~MDNS() {
  77. ESP_LOGI(TAG, "~MDNS()");
  78. mdns_free();
  79. }
  80. void net::MDNS::setHostname(const std::string& hostname) {
  81. ESP_LOGI(TAG, "setHostname(\"%s\")", hostname.c_str());
  82. CHECK(mdns_hostname_set(hostname.c_str()));
  83. }
  84. net::IP *net::MDNS::queryA(const std::string &hostname, int timeoutMs) {
  85. ESP_LOGI(TAG, "queryA(\"%s\")", hostname.c_str());
  86. struct esp_ip4_addr addr{};
  87. addr.addr = 0;
  88. esp_err_t err = mdns_query_a(hostname.c_str(), timeoutMs, &addr);
  89. if (err == ESP_OK) {
  90. auto ip = new net::IP(addr);
  91. ESP_LOGI(TAG, " query A: %s", ip->str().c_str());
  92. return ip;
  93. } else if (err == ESP_ERR_NOT_FOUND) {
  94. ESP_LOGI(TAG, " query A: hostname not found");
  95. return nullptr;
  96. }
  97. CHECK(err);
  98. return nullptr; // unreachable
  99. }
  100. void
  101. net::MDNS::addService(const string &serviceType, int port, const string &instanceName, const net::Proto &proto) {
  102. ESP_LOGI(TAG, "addService(%s, %d, %s, %s)", serviceType.c_str(), port, instanceName.c_str(), protoStr(proto));
  103. mdns_service_add(instanceName == "" ? nullptr : instanceName.c_str(), serviceType.c_str(), protoStr(proto), port,
  104. nullptr, 0);
  105. }
  106. std::vector<net::MDNS::PTRResult> net::MDNS::queryPTR(const string &serviceType, int timeoutMs, net::Proto proto) {
  107. ESP_LOGI(TAG, "queryPTR(%s, %s, %d)", serviceType.c_str(), protoStr(proto), timeoutMs);
  108. std::vector<PTRResult> ret;
  109. mdns_result_t *result = nullptr;
  110. CHECK(mdns_query_ptr(serviceType.c_str(), protoStr(proto), timeoutMs, 20, &result));
  111. for (; result; result = result->next) {
  112. PTRResult tmp{
  113. // .interface = static_cast<Interface>(result->tcpip_if),
  114. // .ipVersion = static_cast<IPVersion>(result->ip_protocol),
  115. .protocol = proto,
  116. .port = result->port,
  117. .instanceName = result->instance_name,
  118. .hostName = result->hostname,
  119. };
  120. auto addr = result->addr;
  121. for (; addr; addr = addr->next) {
  122. if (addr->addr.type == IPADDR_TYPE_V6) {
  123. ESP_LOGW(TAG, "IPv6 support not implemented");
  124. continue;
  125. }
  126. tmp.addresses.push_back(IP(addr->addr.u_addr.ip4));
  127. }
  128. ESP_LOGI(TAG, " result: %s on %s", tmp.instanceName.c_str(), tmp.hostName.c_str());
  129. ret.push_back(tmp);
  130. }
  131. return ret;
  132. }
  133. const char *net::MDNS::protoStr(net::Proto proto) {
  134. return proto == Proto::TCP ? "_tcp" : "_udp";
  135. }