Implemented async MDNS scan
This commit is contained in:
39
CMakeLists.txt
Normal file
39
CMakeLists.txt
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
set(headers
|
||||||
|
src/asyncmdnsresults.h
|
||||||
|
src/asyncmdnssearch.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(sources
|
||||||
|
src/asyncmdnssearch.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(dependencies
|
||||||
|
mdns
|
||||||
|
|
||||||
|
cpputils
|
||||||
|
espchrono
|
||||||
|
espcpputils
|
||||||
|
espwifistack
|
||||||
|
expected
|
||||||
|
fmt
|
||||||
|
)
|
||||||
|
|
||||||
|
idf_component_register(
|
||||||
|
INCLUDE_DIRS
|
||||||
|
src
|
||||||
|
SRCS
|
||||||
|
${headers}
|
||||||
|
${sources}
|
||||||
|
REQUIRES
|
||||||
|
${dependencies}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_options(${COMPONENT_TARGET}
|
||||||
|
PRIVATE
|
||||||
|
-fstack-reuse=all
|
||||||
|
-fstack-protector-all
|
||||||
|
-Wno-unused-function
|
||||||
|
-Wno-deprecated-declarations
|
||||||
|
-Wno-missing-field-initializers
|
||||||
|
-Wno-parentheses
|
||||||
|
)
|
121
src/asyncmdnsresults.h
Normal file
121
src/asyncmdnsresults.h
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// esp-idf includes
|
||||||
|
#include <mdns.h>
|
||||||
|
|
||||||
|
// 3rdparty lib includes
|
||||||
|
#include <arrayview.h>
|
||||||
|
|
||||||
|
class AsyncMdnsResults
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
struct linked_list_iter
|
||||||
|
{
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using value_type = T;
|
||||||
|
using pointer = T*;
|
||||||
|
using reference = T&;
|
||||||
|
|
||||||
|
constexpr linked_list_iter(pointer ptr) noexcept : m_ptr{ptr} {}
|
||||||
|
|
||||||
|
reference operator*() const { return *m_ptr; }
|
||||||
|
pointer operator->() { return m_ptr; }
|
||||||
|
|
||||||
|
linked_list_iter &operator++() { m_ptr = m_ptr->next; return *this; }
|
||||||
|
|
||||||
|
friend bool operator== (const linked_list_iter& a, const linked_list_iter& b) { return a.m_ptr == b.m_ptr; };
|
||||||
|
friend bool operator!= (const linked_list_iter& a, const linked_list_iter& b) { return a.m_ptr != b.m_ptr; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
pointer m_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = mdns_result_t;
|
||||||
|
using pointer = value_type*;
|
||||||
|
using const_pointer = const value_type*;
|
||||||
|
using reference = value_type&;
|
||||||
|
using const_reference = const value_type&;
|
||||||
|
using iterator = linked_list_iter<value_type>;
|
||||||
|
using const_iterator = linked_list_iter<const value_type>;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
// not providing reverse_iterator
|
||||||
|
// not providing const_reverse_iterator
|
||||||
|
|
||||||
|
AsyncMdnsResults() noexcept = default;
|
||||||
|
AsyncMdnsResults(mdns_result_t *results, std::size_t num_results) noexcept :
|
||||||
|
m_results{results}, m_num_results{num_results}
|
||||||
|
{}
|
||||||
|
|
||||||
|
AsyncMdnsResults(const AsyncMdnsResults &) noexcept = delete;
|
||||||
|
AsyncMdnsResults(AsyncMdnsResults &&other) noexcept :
|
||||||
|
m_results{std::move(other.m_results)}, m_num_results{std::move(other.m_num_results)}
|
||||||
|
{
|
||||||
|
other.m_results = {};
|
||||||
|
other.m_num_results = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncMdnsResults &operator=(const AsyncMdnsResults &) noexcept = delete;
|
||||||
|
AsyncMdnsResults &operator=(AsyncMdnsResults &&other)
|
||||||
|
{
|
||||||
|
if (&other != this)
|
||||||
|
{
|
||||||
|
free();
|
||||||
|
m_results = std::move(other.m_results);
|
||||||
|
other.m_results = {};
|
||||||
|
m_num_results = std::move(other.m_num_results);
|
||||||
|
other.m_num_results = {};
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsyncMdnsResults()
|
||||||
|
{
|
||||||
|
free();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Iterators.
|
||||||
|
constexpr iterator begin() noexcept { return iterator(data()); }
|
||||||
|
constexpr const_iterator begin() const noexcept { return const_iterator(data()); }
|
||||||
|
constexpr iterator end() noexcept { return iterator(nullptr); }
|
||||||
|
constexpr const_iterator end() const noexcept { return const_iterator(nullptr); }
|
||||||
|
// not providing rbegin()
|
||||||
|
// not providing rend()
|
||||||
|
constexpr const_iterator cbegin() const noexcept { return const_iterator(data()); }
|
||||||
|
constexpr const_iterator cend() const noexcept { return const_iterator(nullptr); }
|
||||||
|
// not providing crbegin();
|
||||||
|
// not providing crend();
|
||||||
|
|
||||||
|
// Capacity.
|
||||||
|
constexpr size_type size() const noexcept { return m_num_results; }
|
||||||
|
constexpr size_type max_size() const noexcept { return size(); }
|
||||||
|
constexpr bool empty() const noexcept { return data() == nullptr; }
|
||||||
|
|
||||||
|
// Element access.
|
||||||
|
// not providing operator[]
|
||||||
|
// not providing at()
|
||||||
|
// not providing at()
|
||||||
|
constexpr reference front() noexcept { return *data(); }
|
||||||
|
constexpr const_reference front() const noexcept { return *data(); }
|
||||||
|
// not providing back()
|
||||||
|
constexpr pointer data() noexcept { return m_results; }
|
||||||
|
constexpr const_pointer data() const noexcept { return m_results; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void free()
|
||||||
|
{
|
||||||
|
if (m_results)
|
||||||
|
{
|
||||||
|
mdns_query_results_free(m_results);
|
||||||
|
m_results = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
m_num_results = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
mdns_result_t *m_results{};
|
||||||
|
std::size_t m_num_results{};
|
||||||
|
};
|
74
src/asyncmdnssearch.cpp
Normal file
74
src/asyncmdnssearch.cpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#include "asyncmdnssearch.h"
|
||||||
|
|
||||||
|
// esp-idf includes
|
||||||
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
// 3rdparty lib includes
|
||||||
|
#include <cleanuphelper.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr const char * const TAG = "ASYNCMDNS";
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
AsyncMdnsSearch::AsyncMdnsSearch(AsyncMdnsSearch &&other) :
|
||||||
|
m_mdnsScan{std::move(other.m_mdnsScan)}
|
||||||
|
{
|
||||||
|
other.m_mdnsScan = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncMdnsSearch::~AsyncMdnsSearch()
|
||||||
|
{
|
||||||
|
if (searchStarted())
|
||||||
|
deleteSearch();
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncMdnsSearch &AsyncMdnsSearch::operator=(AsyncMdnsSearch &&other)
|
||||||
|
{
|
||||||
|
m_mdnsScan = std::move(other.m_mdnsScan);
|
||||||
|
other.m_mdnsScan = {};
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
tl::expected<void, std::string> AsyncMdnsSearch::startSearch(const char *name, const char *service, const char *proto, uint16_t type, std::chrono::milliseconds timeout, size_t max_results)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "starting search...");
|
||||||
|
|
||||||
|
if (searchStarted())
|
||||||
|
return tl::make_unexpected("last scan not finished yet");
|
||||||
|
|
||||||
|
if (!max_results)
|
||||||
|
return tl::make_unexpected("max_results should be greater than 0");
|
||||||
|
|
||||||
|
m_mdnsScan = mdns_query_async_new(name, service, proto, type, timeout.count(), max_results);
|
||||||
|
if (!searchStarted())
|
||||||
|
return tl::make_unexpected("mdns_query_async_new() returned invalid");
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<AsyncMdnsResults> AsyncMdnsSearch::getResults()
|
||||||
|
{
|
||||||
|
if (!searchStarted())
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "called without a running search");
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
mdns_result_t *results{};
|
||||||
|
uint8_t num_results{};
|
||||||
|
if (!mdns_query_async_get_result(m_mdnsScan, 0, &results, &num_results))
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
deleteSearch();
|
||||||
|
|
||||||
|
return AsyncMdnsResults{results, num_results};
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncMdnsSearch::deleteSearch()
|
||||||
|
{
|
||||||
|
if (!m_mdnsScan)
|
||||||
|
ESP_LOGW(TAG, "no search started!");
|
||||||
|
|
||||||
|
mdns_query_async_delete(m_mdnsScan);
|
||||||
|
m_mdnsScan = nullptr;
|
||||||
|
}
|
36
src/asyncmdnssearch.h
Normal file
36
src/asyncmdnssearch.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <string>
|
||||||
|
#include <chrono>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
// esp-idf includes
|
||||||
|
#include <mdns.h>
|
||||||
|
|
||||||
|
// 3rdparty lib includes
|
||||||
|
#include <tl/expected.hpp>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "asyncmdnsresults.h"
|
||||||
|
|
||||||
|
class AsyncMdnsSearch
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AsyncMdnsSearch() = default;
|
||||||
|
AsyncMdnsSearch(const AsyncMdnsSearch &) = delete;
|
||||||
|
AsyncMdnsSearch(AsyncMdnsSearch &&other);
|
||||||
|
~AsyncMdnsSearch();
|
||||||
|
|
||||||
|
AsyncMdnsSearch &operator=(const AsyncMdnsSearch &) = delete;
|
||||||
|
AsyncMdnsSearch &operator=(AsyncMdnsSearch &&other);
|
||||||
|
|
||||||
|
bool searchStarted() const { return m_mdnsScan; }
|
||||||
|
|
||||||
|
tl::expected<void, std::string> startSearch(const char *name, const char *service, const char *proto, uint16_t type, std::chrono::milliseconds timeout, size_t max_results);
|
||||||
|
std::optional<AsyncMdnsResults> getResults();
|
||||||
|
void deleteSearch();
|
||||||
|
|
||||||
|
private:
|
||||||
|
mdns_search_once_t *m_mdnsScan{};
|
||||||
|
};
|
Reference in New Issue
Block a user