---
name: "gensio_mdns"
section: "3"
platform: "linux"
package: "gensio"
version: "3.0.4-1"
release: "Arch Linux 2026-11-01"
platforms: ["linux"]
url: "https://new.carta.tech/gensio_mdns"
---

# gensio\_mdns(3)

Functions for doing mDNS operations

## NAME

gensio\_alloc\_mdns, gensio\_free\_mdns, gensio\_mdns\_add\_service, gensio\_mdns\_remove\_service, gensio\_mdns\_add\_watch, gensio\_mdns\_remove\_watch - Functions for doing mDNS operations

## SYNOPSIS

**#include \<gensio/gensio\_mdns.h\>**

- **typedef void (\*gensio\_mdns\_done)(struct gensio\_mdns \*m,**

  **void \*userdata);**

- **int gensio\_alloc\_mdns(struct gensio\_os\_funcs \*o,**

  **struct gensio\_mdns \*\*m);**

- **int gensio\_free\_mdns(struct gensio\_mdns \*m, gensio\_mdns\_done done,**

  **void \*userdata);**

- **int gensio\_mdns\_add\_service(struct gensio\_mdns \*m, int interface,**

  **int ipdomain, const char \*name, const char \*type,**\
   **const char \*domain, const char \*host,**\
   **int port, const char \*txt\[\],**\
   **struct gensio\_mdns\_service \*\*s);**

- **typedef void (\*gensio\_mdns\_service\_cb)(struct gensio\_mdns\_service \*service,**

  **enum gensio\_mdns\_service\_event ev,**\
   **const char \*info,**\
   **void \*cb\_data);**

- **int gensio\_mdns\_add\_service2(struct gensio\_mdns \*m, int interface,**

  **int ipdomain, const char \*name, const char \*type,**\
   **const char \*domain, const char \*host,**\
   **int port, const char \*txt\[\],**\
   **gensio\_mdns\_service\_cb cb, void \*cb\_data,**\
   **struct gensio\_mdns\_service \*\*s);**

- **int gensio\_mdns\_remove\_service(struct gensio\_mdns\_service \*s);**

  - **typedef void gensio\_mdns\_watch\_cb(struct gensio\_mdns\_watch \*w,**

  **enum gensio\_mdns\_data\_state state,**\
   **int interface, int ipdomain,**\
   **const char \*name, const char \*type,**\
   **const char \*domain, const char \*host,**\
   **const struct gensio\_addr \*addr, const char \*txt\[\],**\
   **void \*userdata);**

- **int gensio\_mdns\_add\_watch(struct gensio\_mdns \*m, int interface,**

  **int ipdomain, const char \*name, const char \*type,**\
   **const char \*domain, const char \*host,**\
   **gensio\_mdns\_watch\_cb callback, void \*userdata,**\
   **struct gensio\_mdns\_watch \*\*w);**

- **int gensio\_mdns\_remove\_watch(struct gensio\_mdns\_watch \*w);**

  ## DESCRIPTION

These functions and type deal with mDNS (Multicast DNS) discovery of services on a local network.  They can be used to advertise services or find services.  These provide a powerful and easy to use interface to mDNS capabilities.

To do these things, you must first use **gensio\_alloc\_mdns** to allocate an mdns structure with the standard gensio OS functions structure.  You must, of course, do the standard OS functions wait loops and such.  When you are finished, you should free the mdns structure with **gensio\_free\_mdns.** Note that code may still be in mdns callbacks when the free returns, you have to make sure to wait until the done callback is called to know the code is out of all callbacks.  The done callback is optional if you don't care.  Also note that the mdns will not be freed (and done not called) until all the services and watches are freed for it.

For the remaining functions, the *interface* parameter is the system interface number of the network device, and may be -1 to specify all interfaces.  The *ipdomain* parameter is one of:

- *GENSIO\_NETTYPE\_UNSPEC*

  Do both IPV4 and IPV4

- *GENSIO\_NETTYPE\_IPV4*

  IPV4 only

- *GENSIO\_NETTYPE\_IPV6*

  IPV6 only\

The *name, type, domain, and host* parameters are the standard mDNS fields, see documentation on mDNS for details.  The *txt* parameter is for mDNS text fields, and is a standard argv-like array.

Once you have an mdns structure, you can advertise a service on the net with it using **gensio\_mdns\_add\_service2.** That service will continue to be advertised until you call **gensio\_mdns\_remove\_service** on it or your program terminates.  The *domain* and *host* parameters should generally be NULL to take the system defaults.  The *txt* parameter may be NULL if you don't have any.

**gensio\_mdns\_add\_service2** takes a callback, it will be called when the service has been registered, and possible with a new name if there was a name conflict. You may pass in a NULL for the callback if you don't care.  The callback **parameter can take the following values:**

- *GENSIO\_MDNS\_SERVICE\_READY*

  The service is now registered, and the name is the same as the name you passed in.

- *GENSIO\_MDNS\_SERVICE\_READY\_NEW\_NAME*

  The service is now registered, but the name was changed, it will be in the info parameter.

- *GENSIO\_MDNS\_SERVICE\_REMOVED*

  You requested the service be removed, the remove is now complete and the callback will not be called again.

- *GENSIO\_MDNS\_SERVICE\_ERROR*

  An error occurred as part of service registration.

There is a **gensio\_mdns\_add\_service** function for backwards compatibility, it is equivalent to calling **gensio\_mdns\_add\_service2** with a NULL callback.  Don't use it in new code.

To find services on the network, you add a watch with **gensio\_mdns\_add\_watch.** Any service that matches your query will be reported with the callback functions and all fields will be provided in the callback.  Once you are done with a watch, you may call **gensio\_mdns\_remove\_watch** Note that code may still be in mdns callbacks when the remove returns, you have to make sure to wait until the done callback is called to know the code is out of all callbacks.  The done callback is optional if you don't care.

Some MDNS libraries do not support an NULL **type** for the watch, and some do.  For portable code, always specify the watch.  If the library does not support a null **type** the function will return **GE\_INCONSISTENT.**

The watch callback state has three possible values:

- *GENSIO\_MDNS\_WATCH\_NEW\_DATA*

  This is a new entry being reported.

- *GENSIO\_MDNS\_WATCH\_DATA\_GONE*

  An entry that was previously reported as gone away.

- *GENSIO\_MDNS\_WATCH\_ALL\_FOR\_NOW*

  This is called one time after the watch is created, it reports that all currently known entries have been reported.  New ones may be reported in the future, but those will have been dynamically added later.

In the watch callback, you must make copies of all the strings and addresses passed to you to keep them.  Their continued existence is not guaranteed.

In watches, all of the string fields may be NULL, meaning you want to take anything in that field.  So if all the strings are NULL and the interface is -1 and the ipdomain is *GENSIO\_NETTYPE\_UNSPEC* you will get all of the fields.

## STRING VALUES FOR WATCHES

The string values to the watch add function may use regular expressions.  If the string starts with '%', then the data after it is treated as a regular expression and fields are matched against that.  See the [regex(7)](/regex/7.md) man page for details.

Globs are supported on some platforms, but their use is discouraged because they aren't available on some platforms.  If the string starts with '@', the the data after it is treated as a standard glob.  See the [glob(7)](/glob/7.md) man page for details.  An error will be returned if the platform doesn't have glob matching.

If the string starts with '=', an exact comparison is done with the data after it.

If the string starts with a-z0-9\_ or a space, then an exact string comparison is done, including the first character.

The behavior of matching for any other starting character is undefined.  In general, you should always use '@', '%', or '=' as the starting character of all your query strings to be sure.

## RETURN VALUES

Zero is returned on success, or a gensio error on failure.

## SEE ALSO

[gensio\_err(3)](/gensio_err/3.md), [gensio\_os\_funcs(3)](/gensio_os_funcs/3.md), [regex(7)](/regex/7.md), [glob(7)](/glob/7.md)
