Эта библиотека предоставляет кроссплатформенную библиотеку mDNS и DNS-DS только для заголовков на языке C. Последняя версия исходного кода всегда доступна по адресу
https://github.com/mjansson/mdns
Эта библиотека находится в свободном доступе; вы можете распространять его и/или изменять без каких-либо ограничений.
Создано Маттиасом Янссоном (@maniccoder)
Дискорд-сервер для обсуждений https://discord.gg/M8BwTQrt6c
Библиотека выполняет обнаружение и обслуживание DNS-SD, а также одноразовый запрос и ответ mDNS с одной записью. Библиотека не выделяет память, все используемые буферы должны быть переданы вызывающей стороне. Пользовательские данные для использования при обработке можно передавать с помощью непрозрачного указателя пользовательских данных.
Тестовый исполняемый файл mdns.c
демонстрирует использование всех функций, включая обнаружение, запросы и ответы служб. Документация здесь намеренно скудна, пример кода хорошо документирован и должен содержать все детали.
Сокет для связи mDNS может быть открыт библиотекой с помощью mdns_socket_open_ipv4
или mdns_socket_open_ipv6
или путем инициализации существующего сокета с помощью mdns_socket_setup_ipv4
или mdns_socket_setup_ipv6
. Функции открытия/настройки сокета инициализируют сокет с членством в многоадресной рассылке (включая обратную связь) и переводят его в неблокирующий режим.
Вызовите mdns_socket_close
, чтобы закрыть сокет, открытый с помощью mdns_socket_open_ipv4
или mdns_socket_open_ipv6
.
Чтобы открыть/настроить сокет для одноразовых запросов, вы можете передать адрес сокета с нулевым указателем или установить порт в переданном адресе сокета на 0. Это привяжет сокет к случайному эфемерному локальному порту UDP, как того требуют RFC для одноразовые запросы. НЕ следует привязываться к порту 5353 при выполнении одноразовых запросов (подробности см. в RFC).
Чтобы открыть/настроить сокет для обслуживания, отвечая на входящие запросы, вам необходимо передать структуру адреса сокета с портом, установленным на 5353 (определенный MDNS_PORT в заголовке). Вы не можете выбрать другой порт, иначе вы не будете получать входящие запросы.
Чтобы выполнить обнаружение или запросы к сетевому интерфейсу по умолчанию, вы можете передать нулевой указатель в качестве адреса сокета в функциях создания/настройки сокета. Это привяжет сокет к сетевому интерфейсу по умолчанию. В противном случае вам следует перечислить доступные интерфейсы и передать соответствующий адрес сокета в функцию создания/настройки. См. пример программы в mdns.c
где приведен пример реализации этого как для IPv4, так и для IPv6.
Если вы хотите, чтобы служба mDNS отвечала на входящие запросы, вам не нужно перечислять интерфейсы для ответа службы на всех интерфейсах, поскольку сокеты получают данные со всех интерфейсов. См. пример программы в mdns.c
, где приведен пример настройки служебного сокета для IPv4 и IPv6.
Чтобы отправить запрос на обнаружение службы DNS-SD, используйте mdns_discovery_send
. При этом будет отправлен один многоадресный пакет (одна запись вопроса PTR для _services._dns-sd._udp.local.
) с запросом одноадресного ответа.
Чтобы прочитать ответы обнаружения, используйте mdns_discovery_recv
. Все записи, полученные с момента последнего вызова, будут переданы обратному вызову, указанному при вызове функции. Тип записи будет одним из MDNS_ENTRYTYPE_ANSWER
, MDNS_ENTRYTYPE_AUTHORITY
и MDNS_ENTRYTYPE_ADDITIONAL
.
Чтобы отправить одноразовый запрос mDNS для одной записи, используйте mdns_query_send
. При этом будет отправлен один многоадресный пакет для данной записи и имени (например, запись PTR для _http._tcp.local.
). При желании вы можете передать идентификатор запроса для последующей фильтрации ответов (хотя это не рекомендуется RFC) или передать 0 для обеспечения полного соответствия. Функция возвращает идентификатор запроса, связанный с этим запросом, который, если он ненулевой, может использоваться для фильтрации ответов в mdns_query_recv
. Если сокет привязан к порту 5353, запрашивается многоадресный ответ, в противном случае — одноадресный ответ.
Чтобы прочитать ответы на запросы, используйте mdns_query_recv
. Все записи, полученные с момента последнего вызова, будут переданы обратному вызову, указанному при вызове функции. Если параметр query_id
не равен нулю, функция отфильтрует любой ответ с идентификатором запроса, который не соответствует данному идентификатору запроса. Тип записи будет одним из MDNS_ENTRYTYPE_ANSWER
, MDNS_ENTRYTYPE_AUTHORITY
и MDNS_ENTRYTYPE_ADDITIONAL
.
Обратите внимание, что сокет, открытый для однократных запросов из временного порта, не будет получать никаких незапрошенных ответов (объявлений), поскольку они отправляются в виде многоадресной рассылки на порт 5353.
Чтобы отправить несколько запросов в одном пакете, используйте mdns_multiquery_send
, который принимает массив и количество имен служб и типов записей для запроса.
Для прослушивания входящих запросов DNS-SD и запросов mDNS сокет можно открыть/настроить на интерфейсе по умолчанию, передав 0 в качестве адреса сокета в вызове функций открытия/настройки сокета (сокет будет получать данные со всех сетевых интерфейсов). Затем вызовите mdns_socket_listen
либо при уведомлении о входящих данных, либо установив режим блокировки и вызвав mdns_socket_listen
для блокировки до тех пор, пока данные не станут доступны и не проанализированы.
Тип записи, передаваемый обратному вызову, будет MDNS_ENTRYTYPE_QUESTION
, а тип записи указывает, какую запись следует ответить. Пример программы реагирует на записи SRV, PTR, A и AAAA. Используйте функцию mdns_string_extract
, чтобы получить строку имени запрошенной служебной записи.
Если имя служебной записи — _services._dns-sd._udp.local.
вам следует использовать mdns_discovery_answer
для отправки записей о предоставляемых вами услугах (DNS-SD).
Если имя записи службы относится к предоставляемой вами услуге, используйте mdns_query_answer_unicast
или mdns_query_answer_multicast
в зависимости от флага типа ответа в вопросе, чтобы отправить сведения об услуге обратно в ответ на запрос.
См. реализацию тестового исполняемого файла для получения более подробной информации о том, как обрабатывать параметры данных функций.
Если вы предоставляете службу mDNS, прослушивающую и отвечающую на запросы через порт 5353, рекомендуется отправлять объявление при запуске вашей службы (в качестве незапрошенного ответа). Используйте mdns_announce_multicast
, чтобы объявить записи для вашей службы при запуске, и mdns_goodbye_multicast
, чтобы объявить об окончании службы при завершении.
Файл mdns.c
содержит реализацию тестового исполняемого файла, использующую библиотеку для выполнения запросов DNS-SD и mDNS. Скомпилируйте в исполняемый файл и запустите, чтобы увидеть параметры командной строки для режимов обнаружения, запроса и обслуживания.
cl mdns.c /Zi /Fdmdns.pdb /link /out:mdns.exe ws2_32.lib iphlpapi.lib
gcc -o mdns mdns.c
clang -o mdns mdns.c
FetchContent
или установите и find_package
mdns/20200130
и find_package
-> https://conan.io/center/mdns/20200130vcpkg install mdns
и find_package