\section{MDNS client}

% Short description/overview of module functions
This module can register DNS resource records on the network via Multicast DNS as either \textbf{\emph{shared}} or \textbf{\emph{unique}} records. Unique records are, as the name implies, unique on the network (the record-name and -type combination is unique) and one single host has claimed the ownership of them. Shared records are records that are not unique on the network, which means multiple hosts can register records with the same record-name and -type combination. For more information on shared and unique resource record sets, see RFC6762.

Unique records are, as it should, defended when somebody else tries to claim the same unique records. When hosts detect such a defense of another host while registering their own records, the conflict will be resolved by choosing another name for the records and another attempt is made to register those new records.

This module only supplies the mechanisms of record registration and resolving on the network, it doesn't parses the contents of them, that's up to the application.

\subsection{pico$\_$mdns$\_$init}

\subsubsection*{Description}
Initialises the entire mDNS-module and sets the hostname for this machine. Sets up the global mDNS socket properly and calls callback when succeeded. Only when the module is properly initialised, records can be registered on the network.
\subsubsection*{Function prototype}
\begin{verbatim}
int pico_mdns_init( const char *hostname, 
                    struct pico_ip4 address, 
                    void (*callback)(pico_mdns_rtree *, char *, void *), 
                    void *arg );
\end{verbatim}

\subsubsection*{Parameters}
\begin{itemize}[noitemsep]
\item \texttt{hostname} - Hostname to register for this machine. Should end with \'.local\'.
\item \texttt{address} - IPv4-address of this machines interface to generate a hostname record from.
\item \texttt{cb$\_$initialised} - Callback-function that is called when the initialisation process is done. This will also get called when asynchronous conflicts occur for successfully registered records during run-time. The mDNS-record tree contains the registered records, the char-buffer contains the registered hostname and the void-pointer contains the passed argument.
\item \texttt{arg} - Argument for callback supplied by user. This can be used if you want to pass some variable into your callback function.
\end{itemize}

\subsubsection*{Return value}
Returns 0 when the module is properly initialised and the host started registering the hostname. Returns something else went the host failed initialising the module or registering the hostname. \texttt{pico$\_$err} is set appropriately.

\subsubsection*{Errors}
\begin{itemize}[noitemsep]
\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument
\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space
\end{itemize}

\subsubsection*{Example}
\begin{verbatim}
pico_mdns_init("host.local", address, &mdns_init_callback, NULL);
\end{verbatim}


\subsection{pico$\_$mdns$\_$get$\_$hostname}

\subsubsection*{Description}
Get the current hostname for this machine.

\subsubsection*{Function prototype}
\begin{verbatim}
const char * pico_mdns_get_hostname( void );
\end{verbatim}

\subsubsection*{Return value}
Returns the current hostname for this machine when the module is initialised, returns NULL when the module is not initialised.

\subsubsection*{Errors}
\begin{itemize}[noitemsep]
\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument
\end{itemize}

\subsubsection*{Example}
\begin{verbatim}
char *url = pico_mdns_get_hostname();
\end{verbatim}


\subsection{pico$\_$mdns$\_$set$\_$hostname}

\subsubsection*{Description}
Tries to claim a hostname for this machine. Claims automatically a unique A record with the IPv4-address of this host. The hostname won't be set directly when this functions returns, but only if the claiming of the unique record succeeded. Init-callback specified when initialising the module will be called when the hostname-record is successfully registered.

\subsubsection*{Function prototype}
\begin{verbatim}
int pico_mdns_tryclaim_hostname( const char *url, void *arg );
\end{verbatim}

\subsubsection*{Parameters}
\begin{itemize}[noitemsep]
\item \texttt{url} - URL to set the hostname to. Should end with \'.local\'.
\item \texttt{arg} - Argument for init-callback supplied by user. This can be used if you want to pass some variable into your callback function.
\end{itemize}

\subsubsection*{Return value}
Returns 0 when the host started registering the hostname-record successfully, returns something else when it didn't succeed. \texttt{pico$\_$err} is set appropriately.

\subsubsection*{Errors}
\begin{itemize}[noitemsep]
\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument
\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space
\end{itemize}

\subsubsection*{Example}
\begin{verbatim}
int ret = pico_mdns_tryclaim_hostname("device.local", NULL);
\end{verbatim}


\subsection{pico$\_$mdns$\_$claim}

\subsubsection*{Description}
Claims all different mDNS records in a tree in a single API-call. All records in the mDNS record-tree are registered in a single new claim-session.

\subsubsection*{Function prototype}
\begin{verbatim}
int pico_mdns_claim( pico_mdns_rtree record_tree,
                     void (*callback)(pico_mdns_rtree *,  char *, void *),
                     void *arg );
\end{verbatim}

\subsubsection*{Parameters}
\begin{itemize}[noitemsep]
\item \texttt{record$\_$tree} - mDNS record-tree with records to register on the network via Multicast DNS. Can contain \textbf{\emph{unique records}} as well as \textbf{\emph{shared records}}. Declare a mDNS record-tree with the macro 'PICO$\_$MDNS$\_$RTREE$\_$DECLARE(name)', which is actually just a pico$\_$tree-struct, with a comparing-function already set. Records can be added with the preprocessor macro 'PICO$\_$MDNS$\_$RTREE$\_$ADD(pico$\_$mdns$\_$rtree *, struct pico$\_$mdns$\_$record *)'. To create mDNS records see 'pico$\_$mdns$\_$record$\_$create'.
\item \texttt{callback} - Callback function that gets called when \textbf{\emph{ALL}} records in the tree are successfully registered on the network. Records in the returned tree can differ from records originally registered due to conflict-resolution and such.
\item \texttt{arg} - Argument for callback supplied by user. This can be used if you want to pass some variable into your callback function.
\end{itemize}

\subsubsection*{Return value}
Returns 0 when the host started registering the record successfully, returns something else when it didn't succeed. \texttt{pico$\_$err} is set appropriately.

\subsubsection*{Errors}
\begin{itemize}[noitemsep]
\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument
\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space
\end{itemize}

\subsubsection*{Example}
\begin{verbatim}
...
PICO_MDNS_RTREE_DECLARE(rtree);
PICO_MDNS_RTREE_ADD(&rtree, &record);
int ret = pico_mdns_claim(rtree, &claimed_cb, NULL);
\end{verbatim}


\subsection{pico$\_$mdns$\_$getrecord}

\subsubsection*{Description}
API-call to query a record with a certain URL and type. First checks the cache for this record. If no cache-entry is found, a query will be sent on the wire for this record.

\subsubsection*{Function prototype}
\begin{verbatim}
int pico_mdns_getrecord( const char *url, uint16_t type,
                         void (*callback)(pico_mdns_rtree *, char *, void *),
                         void *arg );
\end{verbatim}

\subsubsection*{Parameters}
\begin{itemize}[noitemsep]
\item \texttt{url} - URL of the DNS name to query records for.
\item \texttt{type} - DNS type of the records to query for on the network.
\item \texttt{callback} - Callback to call when records are found or answers to the query are received. This functions can get called multiple times when multiple answers are possible (e.g. with shared records). It's up to the application to aggregate all these received answers, this is possible with a static variable of the type pico$\_$mdns$\_$rtree.
\item \texttt{arg} - Argument for callback supplied by user. This can be used if you want to pass some variable into your callback function.
\end{itemize}

\subsubsection*{Return value}
Returns 0 when the host started querying for these records successfully or the records are found in the cache. Returns something else when it didn't succeed. \texttt{pico$\_$err} is set appropriately.

\subsubsection*{Errors}
\begin{itemize}[noitemsep]
\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument
\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space
\end{itemize}

\subsubsection*{Example}
\begin{verbatim}
int ret = pico_mdns_getrecord("_ipp._tcp.local", PICO_DNS_TYPE_PTR, &query_cb, NULL);
\end{verbatim}


\subsection{pico$\_$mdns$\_$record$\_$create}

\subsubsection*{Description}
Creates a single standalone mDNS resource record with given name, type and data to register on the network.

\subsubsection*{Function prototype}
\begin{verbatim}
struct pico_mdns_record *pico_mdns_record_create( const char *url,
                                                  void *_rdata,
                                                  uint16_t datalen,
                                                  uint16_t rtype,
                                                  uint32_t rttl,
                                                  uint8_t flags );
\end{verbatim}

\subsubsection*{Parameters}
\begin{itemize}[noitemsep]
\item \texttt{url} - DNS resource record name in URL format. Will be converted to DNS name notation format.
\item \texttt{$\_$rdata} - Memory buffer with data to insert in the resource record. If data of record should contain a DNS name, the name in the databuffer needs to be in URL-format.
\item \texttt{datalen} - The exact length in bytes of the $\_$rdata-buffer. If data of record should contain a DNS name (f.e. with PICO$\_$DNS$\_$TYPE$\_$PTR), datalen needs to be pico$\_$dns$\_$strlen($\_$rdata).
\item \texttt{rtype} - DNS type of the resource record to be.
\item \texttt{ttl} - TTL of the resource record to be when registered on the network. In seconds.
\item \texttt{flags} - With this parameter, you can specify a record as either a shared record or a unique record with respectively PICO$\_$MDNS$\_$RECORD$\_$SHARED- or PICO$\_$MDNS$\_$RECORD$\_$UNIQUE-preprocessor defines. Records are by default registered as unique.
\end{itemize}

\subsubsection*{Return value}
Returns a pointer to the newly created record on success, returns NULL on failure. \texttt{pico$\_$err} is set appropriately.

\subsubsection*{Errors}
\begin{itemize}[noitemsep]
\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument
\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space
\end{itemize}

\subsubsection*{Example}
\begin{verbatim}
pico_ip4 ip = 0;
pico_string_to_ipv4("10.10.0.5", &(ip.addr));
struct pico_mdns_record *record = pico_mdns_record_create("foo.local", 
                                                          &(ip.addr),
                                                          PICO_SIZE_IP4,
                                                          PICO_DNS_TYPE_ANY,
                                                          120,
                                                    PICO_MDNS_RECORD_UNIQUE);
\end{verbatim}


\subsection{IS$\_$HOSTNAME$\_$RECORD}

\subsubsection*{Description}
The initialisation-callback can get called multiple times during run-time due to \emph{passive conflict detection}. A passive conflict occurs for unique records when a faulty Multicast DNS-responder doesn't apply conflict resolution after an occurred conflict. A passive conflict can also occur when a peer registers a \textbf{\emph{shared}} record with the same name and type combination as a \textbf{\emph{unique}} record that the local host already successfully registered on the network. Because of that, shared records have priority over unique records, so unfortunately the local host has to apply the conflict resolution-mechanism to it's earlier uniquely verified record. To be able to notify the application of an updated unique record, the callback gets called given in the initialisation-function. But since that callback maybe parses the returned records as the hostname-records and this isn't necessarily the case when a passive conflict occurs, a mechanism is needed to differ hostname-records from other records. This preprocessor-macro allows this.

\subsubsection*{Function prototype}
\begin{verbatim}
IS_HOSTNAME_RECORD(record)
\end{verbatim}

\subsubsection*{Parameters}
\begin{itemize}[noitemsep]
\item \texttt{record} - mDNS resource record
\end{itemize}

\subsubsection*{Return value}
Returns 1 when this record is a hostname record, returns 0 when it's not or when given pointer is a NULL pointer.