Files
OrcaSlicer-KX/deps_src/mdns/cxmdns.cpp
grant0013 d643701529 harktech: move vendored mdns into deps_src/ per repo convention
Per @SoftFever review on #13752, third-party vendored libraries belong in
deps_src/ alongside expat, imgui, hidapi, etc.

- All 5 files (mdns.{h,c}, cxmdns.{h,cpp}, NOTICE.md) move from
  src/slic3r/Utils/mdns/ to deps_src/mdns/.
- deps_src/mdns/CMakeLists.txt builds mdns as a STATIC library and scopes
  the MSVC Iphlpapi/Ws2_32 link requirement to that target instead of
  libslic3r_gui's global MSVC block.
- deps_src/CMakeLists.txt gains add_subdirectory(mdns).
- src/slic3r/CMakeLists.txt drops the inline source listings and links
  libslic3r_gui against the new mdns target; MSVC block keeps only
  Setupapi.lib.
- src/slic3r/Utils/CrealityHostDiscovery.cpp #include updated to use the
  include dir exposed by the new mdns target.

Verified by a clean Linux build (orca-slicer links successfully).
2026-05-20 11:16:13 +00:00

257 lines
7.7 KiB
C++

#include"cxmdns.h"
#include"mdns.h"
#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS 1
#endif
#include <stdio.h>
#include<string.h>
#include <errno.h>
#include <signal.h>
#ifdef _WIN32
#include <winsock2.h>
#include <iphlpapi.h>
#define sleep(x) Sleep(x * 1000)
#else
#include <netdb.h>
#include <ifaddrs.h>
#include <net/if.h>
#endif
// Alias some things to simulate recieving data to fuzz library
#if defined(MDNS_FUZZING)
#define recvfrom(sock, buffer, capacity, flags, src_addr, addrlen) ((mdns_ssize_t)capacity)
#define printf
#endif
#include "mdns.h"
#if defined(MDNS_FUZZING)
#undef recvfrom
#endif
namespace cxnet
{
template <typename F>
mdns_record_callback_fn lambda2function(F lambda)
{
static auto lambdabak = lambda;
return [](int sock, const struct sockaddr* from, size_t addrlen,
mdns_entry_type_t entry, uint16_t query_id, uint16_t rtype,
uint16_t rclass, uint32_t ttl, const void* data, size_t size,
size_t name_offset, size_t name_length, size_t record_offset,
size_t record_length, void* user_data)->int {lambdabak(sock, from, addrlen, entry, query_id, rtype, rclass, ttl, data, size, name_offset, name_length, record_offset, record_length, user_data); return 0; };
}
volatile sig_atomic_t running = 1;
#ifdef _WIN32
BOOL console_handler(DWORD signal) {
if (signal == CTRL_C_EVENT) {
running = 0;
}
return TRUE;
}
#else
void signal_handler(int signal) {
running = 0;
}
#endif
void recvMachineInfoFromSocket(int sock, void* buffer, size_t capacity, const std::vector<std::string>& prefix, std::vector<machine_info>& retmachineInfos, int recIndex)
{
struct sockaddr_in6 addr;
struct sockaddr* saddr = (struct sockaddr*)&addr;
socklen_t addrlen = sizeof(addr);
memset(&addr, 0, sizeof(addr));
#ifdef __APPLE__
saddr->sa_len = sizeof(addr);
#endif
mdns_ssize_t ret = recvfrom(sock, (char*)buffer, (mdns_size_t)capacity, 0, saddr, &addrlen);
if (ret <= 0)
return;
size_t data_size = (size_t)ret;
//size_t records = 0;
const uint16_t* data = (uint16_t*)buffer;
uint16_t query_id = mdns_ntohs(data++);
uint16_t flags = mdns_ntohs(data++);
uint16_t questions = mdns_ntohs(data++);
uint16_t answer_rrs = mdns_ntohs(data++);
uint16_t authority_rrs = mdns_ntohs(data++);
uint16_t additional_rrs = mdns_ntohs(data++);
// According to RFC 6762 the query ID MUST match the sent query ID (which is 0 in our case)
if (query_id || (flags != 0x8400))
return; // Not a reply to our question
// It seems some implementations do not fill the correct questions field,
// so ignore this check for now and only validate answer string
// if (questions != 1)
// return 0;
int i;
for (i = 0; i < questions; ++i) {
size_t offset = MDNS_POINTER_DIFF(data, buffer);
size_t verify_offset = 12;
// Verify it's our question, _services._dns-sd._udp.local.
if (!mdns_string_equal(buffer, data_size, &offset, mdns_services_query,
sizeof(mdns_services_query), &verify_offset))
return;
data = (const uint16_t*)MDNS_POINTER_OFFSET(buffer, offset);
uint16_t rtype = mdns_ntohs(data++);
uint16_t rclass = mdns_ntohs(data++);
// Make sure we get a reply based on our PTR question for class IN
if ((rtype != MDNS_RECORDTYPE_PTR) || ((rclass & 0x7FFF) != MDNS_CLASS_IN))
return;
}
for (i = 0; i < answer_rrs; ++i) {
size_t offset = MDNS_POINTER_DIFF(data, buffer);
size_t verify_offset = 12;
// Verify it's an answer to our question, _services._dns-sd._udp.local.
size_t name_offset = offset;
int is_answer = mdns_string_equal(buffer, data_size, &offset, mdns_services_query,
sizeof(mdns_services_query), &verify_offset);
if (!is_answer && !mdns_string_skip(buffer, data_size, &offset))
break;
size_t name_length = offset - name_offset;
if ((offset + 10) > data_size)
return;
data = (const uint16_t*)MDNS_POINTER_OFFSET(buffer, offset);
uint16_t rtype = mdns_ntohs(data++);
uint16_t rclass = mdns_ntohs(data++);
uint32_t ttl = mdns_ntohl(data);
data += 2;
uint16_t length = mdns_ntohs(data++);
if (length > (data_size - offset))
return;
static char addrbuf[64];
static char entrybuf[256];
static char namebuf[256];
if (is_answer) {
offset = MDNS_POINTER_DIFF(data, buffer);
(void)sizeof(sock);
(void)sizeof(query_id);
(void)sizeof(name_length);
//(void)sizeof(0);
mdns_string_t fromaddrstr = ip_address_to_string(addrbuf, sizeof(addrbuf), saddr, addrlen);
mdns_string_t entrystr =
mdns_string_extract(buffer, data_size, &name_offset, entrybuf, sizeof(entrybuf));
if (rtype == MDNS_RECORDTYPE_PTR) {
mdns_string_t namestr = mdns_record_parse_ptr(buffer, data_size, offset, length,
namebuf, sizeof(namebuf));
if (!namestr.str || namestr.length == 0) {
return;
}
const std::string answer_name(namestr.str, namestr.length);
bool bFound = false;
for (const auto& item : prefix)
{
if (answer_name.find(item) != std::string::npos)
bFound = true;
}
if (!bFound)
{
return;
}
char ip[16] = { 0 };
sscanf(fromaddrstr.str, "%[^:]", ip);
retmachineInfos.push_back({ ip, answer_name });
}
}
}
}
std::vector<machine_info> syncDiscoveryService(const std::vector<std::string>& prefix)
{
std::vector<machine_info> retmachineInfos;
const char* hostname = "cxslice-host";
// Initialize network environment
#ifdef _WIN32
WORD versionWanted = MAKEWORD(1, 1);
WSADATA wsaData;
if (WSAStartup(versionWanted, &wsaData)) {
printf("Failed to initialize WinSock\n");
return retmachineInfos;
}
char hostname_buffer[256];
DWORD hostname_size = (DWORD)sizeof(hostname_buffer);
if (GetComputerNameA(hostname_buffer, &hostname_size))
hostname = hostname_buffer;
SetConsoleCtrlHandler(console_handler, TRUE);
#else
char hostname_buffer[256];
size_t hostname_size = sizeof(hostname_buffer);
if (gethostname(hostname_buffer, hostname_size) == 0)
hostname = hostname_buffer;
signal(SIGINT, signal_handler);
#endif
int sockets[32];
int num_sockets = open_client_sockets(sockets, sizeof(sockets) / sizeof(sockets[0]), 0);
if (num_sockets <= 0) {
printf("Failed to open any client sockets\n");
#ifdef _WIN32
WSACleanup();
#endif
return retmachineInfos;
}
printf("Opened %d socket%s for DNS-SD\n", num_sockets, num_sockets > 1 ? "s" : "");
printf("Sending DNS-SD discovery\n");
for (int isock = 0; isock < num_sockets; ++isock) {
if (mdns_discovery_send(sockets[isock]))
printf("Failed to send DNS-DS discovery: %s\n", strerror(errno));
}
size_t capacity = 2048;
void* buffer = malloc(capacity);
size_t recordNum = 0;
void* user_data = 0;
// This is a simple implementation that loops for 5 seconds or as long as we get replies
int res;
printf("Reading DNS-SD replies\n");
do {
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
int nfds = 0;
fd_set readfs;
FD_ZERO(&readfs);
for (int isock = 0; isock < num_sockets; ++isock) {
if (sockets[isock] >= nfds)
nfds = sockets[isock] + 1;
FD_SET(sockets[isock], &readfs);
}
res = select(nfds, &readfs, 0, 0, &timeout);
if (res > 0) {
for (int isock = 0; isock < num_sockets; ++isock) {
if (FD_ISSET(sockets[isock], &readfs)) {
// records += mdns_discovery_recv(sockets[isock], buffer, capacity, query_callback,
// 0);
recvMachineInfoFromSocket(sockets[isock], buffer, capacity, prefix, retmachineInfos, isock);
recordNum++;
}
}
}
} while (res > 0);
free(buffer);
//
for (int isock = 0; isock < num_sockets; ++isock)
mdns_socket_close(sockets[isock]);
printf("Closed socket%s\n", num_sockets ? "s" : "");
#ifdef _WIN32
WSACleanup();
#endif
return std::move(retmachineInfos);
}
}