Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add mdns #974

Merged
merged 12 commits into from
Mar 16, 2020
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: add mdns
gocarlos committed Feb 25, 2020
commit 5c92925187bd5548159120dc9f7098728f9210a5
18 changes: 18 additions & 0 deletions recipes/mdns/all/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 2.8.11)
project(cmake_wrapper)

include(conanbuildinfo.cmake)
conan_basic_setup()

set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

add_library(mdns
source_subfolder/mdns.c)

install(TARGETS mdns
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)

install(FILES source_subfolder/mdns.h
DESTINATION include/mdns)
4 changes: 4 additions & 0 deletions recipes/mdns/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
sources:
"20200218":
sha256: 5f327b56d932ed5c1a28b7b1b1f528ddfbf69cb45bc4a8d38301ab85116e4b0e
url: https://github.com/mjansson/mdns/archive/0f75def961433102dc4848564c1a865f473dfaed.tar.gz
69 changes: 69 additions & 0 deletions recipes/mdns/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import os
from conans import CMake, ConanFile, tools


class MdnsConan(ConanFile):
name = "mdns"
license = "public domain"
homepage = "https://github.com/mjansson/mdns"
url = "https://github.com/conan-io/conan-center-index"
description = """
Public domain mDNS/DNS-SD library in C
"""
topics = ("mdns")
gocarlos marked this conversation as resolved.
Show resolved Hide resolved
exports_sources = "CMakeLists.txt"
settings = "os", "compiler", "build_type", "arch"
options = {
"shared": [True, False],
"fPIC": [True, False],
}
default_options = {
"shared": False,
"fPIC": True
}
generators = "cmake"

_cmake = None

@property
def _source_subfolder(self):
return "source_subfolder"

@property
def _build_subfolder(self):
return "build_subfolder"

def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC

def configure(self):
del self.settings.compiler.libcxx
del self.settings.compiler.cppstd

def source(self):
tools.get(**self.conan_data["sources"][self.version])
extracted_dir = self.name + "-" + \
os.path.basename(
self.conan_data["sources"][self.version]["url"]).split(".")[0]
os.rename(extracted_dir, self._source_subfolder)

def _configure_cmake(self):
if self._cmake:
return self._cmake
self._cmake = CMake(self)
self._cmake.configure(build_folder=self._build_subfolder)
return self._cmake

def build(self):
cmake = self._configure_cmake()
cmake.build()

def package(self):
self.copy("LICENSE", dst='licenses',
src=os.path.join(self._source_subfolder, "license"))
cmake = self._configure_cmake()
cmake.install()

def package_info(self):
self.cpp_info.libs = ["mdns"]
9 changes: 9 additions & 0 deletions recipes/mdns/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
project(test_package)
cmake_minimum_required(VERSION 2.8.11)

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()

add_executable(${PROJECT_NAME} test_package.cpp)
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11)
18 changes: 18 additions & 0 deletions recipes/mdns/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import os

from conans import ConanFile, CMake, tools


class TestConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "cmake"

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def test(self):
if not tools.cross_building(self.settings):
bin_path = os.path.join("bin", "test_package")
bin_path = self.run(bin_path, run_environment=True)
193 changes: 193 additions & 0 deletions recipes/mdns/all/test_package/test_package.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@

#ifdef _WIN32
# define _CRT_SECURE_NO_WARNINGS 1
#endif

#include <mdns/mdns.h>

#include <stdio.h>
#include <errno.h>

#ifdef _WIN32
# define sleep(x) Sleep(x * 1000)
#else
# include <netdb.h>
#endif

static char addrbuffer[64];
static char namebuffer[256];
static mdns_record_txt_t txtbuffer[128];

static mdns_string_t
ipv4_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in* addr) {
char host[NI_MAXHOST] = {0};
char service[NI_MAXSERV] = {0};
int ret = getnameinfo((const struct sockaddr*)addr, sizeof(struct sockaddr_in),
host, NI_MAXHOST, service, NI_MAXSERV,
NI_NUMERICSERV | NI_NUMERICHOST);
int len = 0;
if (ret == 0) {
if (addr->sin_port != 0)
len = snprintf(buffer, capacity, "%s:%s", host, service);
else
len = snprintf(buffer, capacity, "%s", host);
}
if (len >= (int)capacity)
len = (int)capacity - 1;
mdns_string_t str = {buffer, len};
return str;
}

static mdns_string_t
ipv6_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in6* addr) {
char host[NI_MAXHOST] = {0};
char service[NI_MAXSERV] = {0};
int ret = getnameinfo((const struct sockaddr*)addr, sizeof(struct sockaddr_in6),
host, NI_MAXHOST, service, NI_MAXSERV,
NI_NUMERICSERV | NI_NUMERICHOST);
int len = 0;
if (ret == 0) {
if (addr->sin6_port != 0)
len = snprintf(buffer, capacity, "[%s]:%s", host, service);
else
len = snprintf(buffer, capacity, "%s", host);
}
if (len >= (int)capacity)
len = (int)capacity - 1;
mdns_string_t str = {buffer, len};
return str;
}

static mdns_string_t
ip_address_to_string(char* buffer, size_t capacity, const struct sockaddr* addr) {
if (addr->sa_family == AF_INET6)
return ipv6_address_to_string(buffer, capacity, (const struct sockaddr_in6*)addr);
return ipv4_address_to_string(buffer, capacity, (const struct sockaddr_in*)addr);
}

static int
callback(const struct sockaddr* from,
mdns_entry_type_t entry, uint16_t type,
uint16_t rclass, uint32_t ttl,
const void* data, size_t size, size_t offset, size_t length,
void* user_data) {
mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer, sizeof(addrbuffer), from);
const char* entrytype = (entry == MDNS_ENTRYTYPE_ANSWER) ? "answer" :
((entry == MDNS_ENTRYTYPE_AUTHORITY) ? "authority" : "additional");
if (type == MDNS_RECORDTYPE_PTR) {
mdns_string_t namestr = mdns_record_parse_ptr(data, size, offset, length,
namebuffer, sizeof(namebuffer));
printf("%.*s : %s PTR %.*s type %u rclass 0x%x ttl %u length %d\n",
MDNS_STRING_FORMAT(fromaddrstr), entrytype,
MDNS_STRING_FORMAT(namestr), type, rclass, ttl, (int)length);
}
else if (type == MDNS_RECORDTYPE_SRV) {
mdns_record_srv_t srv = mdns_record_parse_srv(data, size, offset, length,
namebuffer, sizeof(namebuffer));
printf("%.*s : %s SRV %.*s priority %d weight %d port %d\n",
MDNS_STRING_FORMAT(fromaddrstr), entrytype,
MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port);
}
else if (type == MDNS_RECORDTYPE_A) {
struct sockaddr_in addr;
mdns_record_parse_a(data, size, offset, length, &addr);
mdns_string_t addrstr = ipv4_address_to_string(namebuffer, sizeof(namebuffer), &addr);
printf("%.*s : %s A %.*s\n",
MDNS_STRING_FORMAT(fromaddrstr), entrytype,
MDNS_STRING_FORMAT(addrstr));
}
else if (type == MDNS_RECORDTYPE_AAAA) {
struct sockaddr_in6 addr;
mdns_record_parse_aaaa(data, size, offset, length, &addr);
mdns_string_t addrstr = ipv6_address_to_string(namebuffer, sizeof(namebuffer), &addr);
printf("%.*s : %s AAAA %.*s\n",
MDNS_STRING_FORMAT(fromaddrstr), entrytype,
MDNS_STRING_FORMAT(addrstr));
}
else if (type == MDNS_RECORDTYPE_TXT) {
size_t parsed = mdns_record_parse_txt(data, size, offset, length,
txtbuffer, sizeof(txtbuffer) / sizeof(mdns_record_txt_t));
for (size_t itxt = 0; itxt < parsed; ++itxt) {
if (txtbuffer[itxt].value.length) {
printf("%.*s : %s TXT %.*s = %.*s\n",
MDNS_STRING_FORMAT(fromaddrstr), entrytype,
MDNS_STRING_FORMAT(txtbuffer[itxt].key),
MDNS_STRING_FORMAT(txtbuffer[itxt].value));
}
else {
printf("%.*s : %s TXT %.*s\n",
MDNS_STRING_FORMAT(fromaddrstr), entrytype,
MDNS_STRING_FORMAT(txtbuffer[itxt].key));
}
}
}
else {
printf("%.*s : %s type %u rclass 0x%x ttl %u length %d\n",
MDNS_STRING_FORMAT(fromaddrstr), entrytype,
type, rclass, ttl, (int)length);
}
return 0;
}

int
main() {
size_t capacity = 2048;
void* buffer = 0;
void* user_data = 0;
size_t records;

#ifdef _WIN32
WORD versionWanted = MAKEWORD(1, 1);
WSADATA wsaData;
WSAStartup(versionWanted, &wsaData);
#endif

int sock = mdns_socket_open_ipv4();
if (sock < 0) {
printf("Failed to open socket: %s\n", strerror(errno));
return -1;
}
printf("Opened IPv4 socket for mDNS/DNS-SD\n");

printf("Sending DNS-SD discovery\n");
if (mdns_discovery_send(sock)) {
printf("Failed to send DNS-DS discovery: %s\n", strerror(errno));
goto quit;
}

printf("Reading DNS-SD replies\n");
buffer = malloc(capacity);
for (int i = 0; i < 10; ++i) {
records = mdns_discovery_recv(sock, buffer, capacity, callback,
user_data);
printf("discovered %zu records\n", records);
sleep(1);
}

printf("Sending mDNS query\n");
if (mdns_query_send(sock, MDNS_RECORDTYPE_PTR,
MDNS_STRING_CONST("_ssh._tcp.local."),
buffer, capacity)) {
printf("Failed to send mDNS query: %s\n", strerror(errno));
goto quit;
}

printf("Reading mDNS replies\n");
for (int i = 0; i < 10; ++i) {
records = mdns_query_recv(sock, buffer, capacity, callback, user_data, 1);
printf("received %zu records for query response\n", records);
sleep(1);
}

quit:
free(buffer);

mdns_socket_close(sock);
printf("Closed socket\n");

#ifdef _WIN32
WSACleanup();
#endif

return 0;
}
4 changes: 4 additions & 0 deletions recipes/mdns/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
versions:
"20200225":
gocarlos marked this conversation as resolved.
Show resolved Hide resolved
folder: "all"