feat: initial commit (migrate from old flowy monorepo)
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
BasedOnStyle: Microsoft
|
||||||
|
TabWidth: 2
|
||||||
|
IndentWidth: 2
|
||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
# This file is used to ignore files which are generated
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
*~
|
||||||
|
*.autosave
|
||||||
|
*.a
|
||||||
|
*.core
|
||||||
|
*.moc
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*_pch.h.cpp
|
||||||
|
*_resource.rc
|
||||||
|
*.qm
|
||||||
|
.#*
|
||||||
|
*.*#
|
||||||
|
core
|
||||||
|
!core/
|
||||||
|
tags
|
||||||
|
.DS_Store
|
||||||
|
.directory
|
||||||
|
*.debug
|
||||||
|
Makefile*
|
||||||
|
*.prl
|
||||||
|
*.app
|
||||||
|
moc_*.cpp
|
||||||
|
ui_*.h
|
||||||
|
qrc_*.cpp
|
||||||
|
Thumbs.db
|
||||||
|
*.res
|
||||||
|
*.rc
|
||||||
|
/.qmake.cache
|
||||||
|
/.qmake.stash
|
||||||
|
|
||||||
|
# qtcreator generated files
|
||||||
|
*.pro.user*
|
||||||
|
*.qbs.user*
|
||||||
|
CMakeLists.txt.user*
|
||||||
|
|
||||||
|
# xemacs temporary files
|
||||||
|
*.flc
|
||||||
|
|
||||||
|
# Vim temporary files
|
||||||
|
.*.swp
|
||||||
|
|
||||||
|
# Visual Studio generated files
|
||||||
|
*.ib_pdb_index
|
||||||
|
*.idb
|
||||||
|
*.ilk
|
||||||
|
*.pdb
|
||||||
|
*.sln
|
||||||
|
*.suo
|
||||||
|
*.vcproj
|
||||||
|
*vcproj.*.*.user
|
||||||
|
*.ncb
|
||||||
|
*.sdf
|
||||||
|
*.opensdf
|
||||||
|
*.vcxproj
|
||||||
|
*vcxproj.*
|
||||||
|
|
||||||
|
# MinGW generated files
|
||||||
|
*.Debug
|
||||||
|
*.Release
|
||||||
|
|
||||||
|
# Python byte code
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Binaries
|
||||||
|
# --------
|
||||||
|
*.dll
|
||||||
|
*.exe
|
||||||
|
|
||||||
|
# Directories with generated files
|
||||||
|
.moc/
|
||||||
|
.obj/
|
||||||
|
.pch/
|
||||||
|
.rcc/
|
||||||
|
.uic/
|
||||||
|
/build*/
|
||||||
|
|
||||||
|
.cache/
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
project(mdns VERSION 0.1 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
set(CMAKE_EXPORT_COMPILATION_DATABASE ON)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||||
|
|
||||||
|
# https://doc.qt.io/qt-6/qt-cmake-policy-qtp0003.html
|
||||||
|
option(BUILD_SHARED_LIBS "Build shared instead of static library" ON)
|
||||||
|
|
||||||
|
find_package(Qt6 6.5 REQUIRED COMPONENTS Core)
|
||||||
|
qt_standard_project_setup(REQUIRES 6.5)
|
||||||
|
qt_policy(SET QTP0003 NEW)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
src/broadcaster.h
|
||||||
|
src/broadcaster.cpp
|
||||||
|
src/scanner.h
|
||||||
|
src/scanner.cpp
|
||||||
|
)
|
||||||
|
qt_add_library(mdns ${SOURCES})
|
||||||
|
|
||||||
|
target_include_directories(mdns PUBLIC src/)
|
||||||
|
|
||||||
|
target_link_libraries(mdns PRIVATE Qt6::Core)
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
install(TARGETS mdns
|
||||||
|
BUNDLE DESTINATION .
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
)
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
This package is a Qt wrapper over [zeroconf](https://github.com/yvz/zeroconf).
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
#include "broadcaster.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <cstring>
|
||||||
|
#include <dns_sd.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
ServiceInfo::ServiceInfo(QString sn, QString st, uint16_t p) : service_name(sn), service_type(st), service_port(p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroadcastWorker::static_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode,
|
||||||
|
const char *name, const char *regtype, const char *domain, void *context)
|
||||||
|
{
|
||||||
|
// Cast the context back to our class instance
|
||||||
|
BroadcastWorker *self = static_cast<BroadcastWorker *>(context);
|
||||||
|
if (errorCode == kDNSServiceErr_NoError)
|
||||||
|
{
|
||||||
|
std::cout << "Service registered successfully!" << std::endl;
|
||||||
|
std::cout << "Service Name: " << name << std::endl;
|
||||||
|
std::cout << "Service Type: " << regtype << std::endl;
|
||||||
|
std::cout << "Domain: " << domain << std::endl;
|
||||||
|
emit self->service_registered();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "Error registering service: " << errorCode << std::endl;
|
||||||
|
emit self->error_occurred("Error registering service.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BroadcastWorker::BroadcastWorker(QObject *parent, ServiceInfo *service) : QThread(parent), m_service_info(service)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroadcastWorker::run()
|
||||||
|
{
|
||||||
|
DNSServiceRef serviceRef;
|
||||||
|
DNSServiceErrorType error;
|
||||||
|
|
||||||
|
// Service parameters
|
||||||
|
std::string service_name = m_service_info->service_name.toStdString();
|
||||||
|
std::string service_type = m_service_info->service_type.toStdString();
|
||||||
|
const char *serviceName = service_name.c_str(); // Can be NULL for automatic naming
|
||||||
|
const char *serviceType = service_type.c_str(); // Service type and protocol
|
||||||
|
const char *serviceDomain = NULL; // NULL for default domain
|
||||||
|
const char *serviceHost = NULL; // NULL for default host
|
||||||
|
uint16_t servicePort = m_service_info->service_port; // Service port in network byte order
|
||||||
|
uint16_t txtLen = 0; // Length of TXT record
|
||||||
|
const void *txtRecord = NULL; // TXT record (can be NULL)
|
||||||
|
|
||||||
|
// Convert port to network byte order
|
||||||
|
servicePort = htons(servicePort);
|
||||||
|
|
||||||
|
// Register the service
|
||||||
|
error = DNSServiceRegister(&serviceRef,
|
||||||
|
0, // Default flags
|
||||||
|
0, // Default interface
|
||||||
|
serviceName, serviceType, serviceDomain, serviceHost, servicePort, txtLen, txtRecord,
|
||||||
|
BroadcastWorker::static_callback,
|
||||||
|
this); // Context pointer
|
||||||
|
|
||||||
|
if (error != kDNSServiceErr_NoError)
|
||||||
|
{
|
||||||
|
std::cerr << "Error registering service: " << error << std::endl;
|
||||||
|
emit error_occurred("Error registering service.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the service registration
|
||||||
|
int dns_sd_fd = DNSServiceRefSockFD(serviceRef);
|
||||||
|
fd_set readfds;
|
||||||
|
struct timeval tv;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
// Keep the service registered until the user terminates the program
|
||||||
|
std::cout << "Service is being broadcasted." << std::endl;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (isInterruptionRequested())
|
||||||
|
{
|
||||||
|
// Clean up
|
||||||
|
DNSServiceRefDeallocate(serviceRef);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FD_ZERO(&readfds);
|
||||||
|
FD_SET(dns_sd_fd, &readfds);
|
||||||
|
|
||||||
|
tv.tv_sec = 1;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
result = select(dns_sd_fd + 1, &readfds, NULL, NULL, &tv);
|
||||||
|
if (result > 0)
|
||||||
|
{
|
||||||
|
DNSServiceProcessResult(serviceRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Broadcaster::Broadcaster(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Broadcaster::~Broadcaster()
|
||||||
|
{
|
||||||
|
if (m_worker)
|
||||||
|
{
|
||||||
|
m_worker->requestInterruption();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Broadcaster::start_broadcasting(ServiceInfo *service)
|
||||||
|
{
|
||||||
|
if (m_worker)
|
||||||
|
{
|
||||||
|
qWarning() << "Already have a worker for broadcasting";
|
||||||
|
emit error_occurred("Already have a worker for broadcasting. Please stop first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_worker = new BroadcastWorker(this, service);
|
||||||
|
connect(m_worker, &BroadcastWorker::error_occurred, this, [this](const QString &message) {
|
||||||
|
emit broadcasting_failure();
|
||||||
|
emit error_occurred(message);
|
||||||
|
});
|
||||||
|
connect(m_worker, &BroadcastWorker::started, this, [this]() { qDebug() << "Broadcast worker started"; });
|
||||||
|
connect(m_worker, &BroadcastWorker::service_registered, this, [this] {
|
||||||
|
set_is_broadcasting(true);
|
||||||
|
qDebug() << "Service registered";
|
||||||
|
});
|
||||||
|
connect(m_worker, &BroadcastWorker::finished, [this] {
|
||||||
|
qDebug() << "Broadcast worker finished";
|
||||||
|
m_worker->deleteLater();
|
||||||
|
m_worker = nullptr;
|
||||||
|
|
||||||
|
set_is_broadcasting(false);
|
||||||
|
});
|
||||||
|
m_worker->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Broadcaster::stop_broadcasting()
|
||||||
|
{
|
||||||
|
if (!m_worker || !m_worker->isRunning())
|
||||||
|
{
|
||||||
|
qWarning() << "Not broadcasting";
|
||||||
|
emit error_occurred("Not broadcasting, can't stop");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_worker->requestInterruption();
|
||||||
|
m_worker->wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Broadcaster::is_broadcasting() const
|
||||||
|
{
|
||||||
|
return m_is_broadcasting;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Broadcaster::set_is_broadcasting(bool new_val)
|
||||||
|
{
|
||||||
|
if (m_is_broadcasting == new_val)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_is_broadcasting = new_val;
|
||||||
|
emit is_broadcasting_changed();
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
#ifndef BROADCASTER_H
|
||||||
|
#define BROADCASTER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
#include <dns_sd.h>
|
||||||
|
|
||||||
|
struct ServiceInfo
|
||||||
|
{
|
||||||
|
QString service_name;
|
||||||
|
/**
|
||||||
|
* @brief e.g. _http._tcp
|
||||||
|
*/
|
||||||
|
QString service_type;
|
||||||
|
uint16_t service_port;
|
||||||
|
|
||||||
|
ServiceInfo(QString sn, QString st, uint16_t sp);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class BroadcastAdvertiser
|
||||||
|
* @brief Runs in another thread to broadcast a given service
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class BroadcastWorker : public QThread
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BroadcastWorker(QObject *parent, ServiceInfo *service_info);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ServiceInfo *m_service_info;
|
||||||
|
void run() override;
|
||||||
|
|
||||||
|
// Static callback wrapper that will be called by the C API
|
||||||
|
static void static_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode,
|
||||||
|
const char *name, const char *regtype, const char *domain, void *context);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void error_occurred(const QString &message);
|
||||||
|
void service_registered();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Broadcaster
|
||||||
|
* @brief Broadcasts a service with given port. It does so continuously in another thread.
|
||||||
|
*/
|
||||||
|
class Broadcaster : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Broadcaster(QObject *parent = nullptr);
|
||||||
|
~Broadcaster();
|
||||||
|
|
||||||
|
bool is_broadcasting() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
/**
|
||||||
|
* @brief Starts broadcasting using the information from the given service.
|
||||||
|
*/
|
||||||
|
void start_broadcasting(ServiceInfo *);
|
||||||
|
/**
|
||||||
|
* @brief Stops broadcasting and does cleanup. Gracefully handles if not currently broadcasting.
|
||||||
|
*/
|
||||||
|
void stop_broadcasting();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void error_occurred(const QString &);
|
||||||
|
void broadcasting_failure();
|
||||||
|
void is_broadcasting_changed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BroadcastWorker *m_worker;
|
||||||
|
|
||||||
|
bool m_is_broadcasting;
|
||||||
|
|
||||||
|
void set_is_broadcasting(bool);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BROADCASTER_H
|
||||||
+186
@@ -0,0 +1,186 @@
|
|||||||
|
#include "scanner.h"
|
||||||
|
#include <arpa/inet.h> // For inet_ntop
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
Scanner::Scanner(QString query, QObject *parent) : m_query(query), QThread(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scanner::run()
|
||||||
|
{
|
||||||
|
DNSServiceRef serviceRef;
|
||||||
|
std::string query = m_query.toStdString();
|
||||||
|
|
||||||
|
DNSServiceErrorType error =
|
||||||
|
DNSServiceBrowse(&serviceRef, 0, 0, query.c_str(), NULL, Scanner::service_browse_callback, this);
|
||||||
|
|
||||||
|
if (error != kDNSServiceErr_NoError)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error browsing services: %d\n", error);
|
||||||
|
emit error_occurred("Error browing services");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the service registration
|
||||||
|
int dns_sd_fd = DNSServiceRefSockFD(serviceRef);
|
||||||
|
fd_set readfds;
|
||||||
|
struct timeval tv;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
// Keep the service registered until the user terminates the program
|
||||||
|
std::cout << "Service is being broadcasted." << std::endl;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (isInterruptionRequested())
|
||||||
|
{
|
||||||
|
// Clean up
|
||||||
|
DNSServiceRefDeallocate(serviceRef);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FD_ZERO(&readfds);
|
||||||
|
FD_SET(dns_sd_fd, &readfds);
|
||||||
|
|
||||||
|
tv.tv_sec = 1;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
result = select(dns_sd_fd + 1, &readfds, NULL, NULL, &tv);
|
||||||
|
if (result > 0)
|
||||||
|
{
|
||||||
|
DNSServiceProcessResult(serviceRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scanner::service_resolve_callback(DNSServiceRef service, DNSServiceFlags flags, uint32_t interface_index,
|
||||||
|
DNSServiceErrorType error_code, const char *full_name, const char *host_target,
|
||||||
|
uint16_t port, uint16_t txt_len, const unsigned char *txt_record, void *context)
|
||||||
|
{
|
||||||
|
Scanner *self = static_cast<Scanner *>(context);
|
||||||
|
if (error_code == kDNSServiceErr_NoError)
|
||||||
|
{
|
||||||
|
printf("Resolved Service: %s\n", full_name);
|
||||||
|
printf("Host: %s\n", host_target);
|
||||||
|
printf("Port: %u\n", ntohs(port)); // Convert the port to host byte order
|
||||||
|
//
|
||||||
|
self->m_current_service_name = QString(full_name);
|
||||||
|
self->m_current_host_target = QString(host_target);
|
||||||
|
self->m_current_port = ntohs(port);
|
||||||
|
|
||||||
|
DNSServiceRef addrRef;
|
||||||
|
DNSServiceErrorType addrError =
|
||||||
|
DNSServiceGetAddrInfo(&addrRef, 0, interface_index, kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6,
|
||||||
|
host_target, Scanner::address_info_callback, self);
|
||||||
|
|
||||||
|
if (addrError != kDNSServiceErr_NoError)
|
||||||
|
{
|
||||||
|
printf("Error getting address info: %d\n", addrError);
|
||||||
|
emit self->error_occurred("Error resolving IP address");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Process the result to get the IP
|
||||||
|
DNSServiceProcessResult(addrRef);
|
||||||
|
DNSServiceRefDeallocate(addrRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Failed to resolve service: %d\n", error_code);
|
||||||
|
emit self->error_occurred("Error resolving service");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scanner::address_info_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
|
||||||
|
DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address,
|
||||||
|
uint32_t ttl, void *context)
|
||||||
|
{
|
||||||
|
Scanner *self = static_cast<Scanner *>(context);
|
||||||
|
if (errorCode == kDNSServiceErr_NoError)
|
||||||
|
{
|
||||||
|
// Convert sockaddr to readable IP address
|
||||||
|
char ip_str[INET6_ADDRSTRLEN]; // Big enough for both IPv4 and IPv6
|
||||||
|
bool is_good_address = false;
|
||||||
|
|
||||||
|
if (address->sa_family == AF_INET)
|
||||||
|
{
|
||||||
|
// IPv4
|
||||||
|
struct sockaddr_in *addr_in = (struct sockaddr_in *)address;
|
||||||
|
inet_ntop(AF_INET, &(addr_in->sin_addr), ip_str, INET_ADDRSTRLEN);
|
||||||
|
|
||||||
|
// Skip link-local addresses (169.254.x.x)
|
||||||
|
uint8_t first_octet = addr_in->sin_addr.s_addr & 0xFF;
|
||||||
|
uint8_t second_octet = (addr_in->sin_addr.s_addr >> 8) & 0xFF;
|
||||||
|
|
||||||
|
if (!(first_octet == 169 && second_octet == 254))
|
||||||
|
{
|
||||||
|
is_good_address = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (address->sa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
// IPv6
|
||||||
|
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)address;
|
||||||
|
inet_ntop(AF_INET6, &(addr_in6->sin6_addr), ip_str, INET6_ADDRSTRLEN);
|
||||||
|
|
||||||
|
// Skip link-local addresses (fe80::)
|
||||||
|
if (!IN6_IS_ADDR_LINKLOCAL(&addr_in6->sin6_addr))
|
||||||
|
{
|
||||||
|
// Only use IPv6 if we have no IPv4 (lower priority)
|
||||||
|
is_good_address = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy(ip_str, "Unknown address type");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("IP Address: %s\n", ip_str);
|
||||||
|
|
||||||
|
// Only emit the signal if this is a good address
|
||||||
|
if (is_good_address)
|
||||||
|
{
|
||||||
|
emit self->service_found(self->m_current_service_name, QString(ip_str), QString(hostname), self->m_current_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Failed to resolve address: %d\n", errorCode);
|
||||||
|
emit self->error_occurred("Error resolving IP address");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scanner::service_browse_callback(DNSServiceRef service, DNSServiceFlags flags, uint32_t interface_index,
|
||||||
|
DNSServiceErrorType error_code, const char *service_name, const char *regtype,
|
||||||
|
const char *reply_domain, void *context)
|
||||||
|
{
|
||||||
|
Scanner *self = static_cast<Scanner *>(context);
|
||||||
|
|
||||||
|
if (error_code == kDNSServiceErr_NoError)
|
||||||
|
{
|
||||||
|
printf("Service found: %s.%s%s\n", service_name, regtype, reply_domain ? reply_domain : "");
|
||||||
|
|
||||||
|
// Now resolve the service to get port and other details
|
||||||
|
DNSServiceRef resolveRef;
|
||||||
|
DNSServiceErrorType resolveError = DNSServiceResolve(&resolveRef, 0, interface_index, service_name, regtype,
|
||||||
|
reply_domain, Scanner::service_resolve_callback, self);
|
||||||
|
|
||||||
|
if (resolveError != kDNSServiceErr_NoError)
|
||||||
|
{
|
||||||
|
printf("Error resolving service: %d\n", resolveError);
|
||||||
|
self->error_occurred("Error resolving service");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Process the resolved service
|
||||||
|
DNSServiceProcessResult(resolveRef);
|
||||||
|
DNSServiceRefDeallocate(resolveRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self->error_occurred("Error browsing dns");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#ifndef SCANNER_H
|
||||||
|
#define SCANNER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
#include <dns_sd.h>
|
||||||
|
|
||||||
|
struct Record
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Scanner
|
||||||
|
* @brief A thread that handles scanning with given mDNS query and returns.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Scanner : public QThread
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @param query: e.g. "_http._tcp"
|
||||||
|
*/
|
||||||
|
explicit Scanner(QString query, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void run() override;
|
||||||
|
|
||||||
|
QString m_query;
|
||||||
|
|
||||||
|
// Caching values to use across callbacks
|
||||||
|
// TODO: pass a context struct around instead of this? or does every callback run sequentially?
|
||||||
|
QString m_current_service_name;
|
||||||
|
QString m_current_host_target;
|
||||||
|
uint16_t m_current_port;
|
||||||
|
|
||||||
|
static void DNSSD_API service_resolve_callback(DNSServiceRef service, DNSServiceFlags flags, uint32_t interface_index,
|
||||||
|
DNSServiceErrorType error_code, const char *full_name,
|
||||||
|
const char *host_target, uint16_t port, uint16_t txt_len,
|
||||||
|
const unsigned char *txt_record, void *context);
|
||||||
|
static void DNSSD_API service_browse_callback(DNSServiceRef service, DNSServiceFlags flags, uint32_t interface_index,
|
||||||
|
DNSServiceErrorType error_code, const char *service_name,
|
||||||
|
const char *regtype, const char *reply_domain, void *context);
|
||||||
|
static void DNSSD_API address_info_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
|
||||||
|
DNSServiceErrorType errorCode, const char *hostname,
|
||||||
|
const struct sockaddr *address, uint32_t ttl, void *context);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void service_found(const QString &service_name, const QString &ip, const QString &host, const uint16_t port);
|
||||||
|
void error_occurred(const QString &message);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SCANNER_H
|
||||||
Reference in New Issue
Block a user