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