1 /*****************************************************************************
2  * This file is part of libmicrodns.
3  *
4  * Copyright © 2014-2016 VideoLabs SAS
5  *
6  * Author: Jonathan Calmels <jbjcalmels@gmail.com>
7  *
8  *****************************************************************************
9  * libmicrodns is released under LGPLv2.1 (or later) and is also available
10  * under a commercial license.
11  *****************************************************************************
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU Lesser General Public License as published by
14  * the Free Software Foundation; either version 2.1 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26 
27 #ifndef MICRODNS_MDNS_H
28 #define MICRODNS_MDNS_H
29 
30 /**
31  * @file microdns.h
32  * @brief main functions to listen and announce services
33  */
34 
35 #include <stdbool.h>
36 
37 #include "rr.h"
38 
39 # ifdef __cplusplus
40 extern "C" {
41 # endif
42 
43 #if defined(_MSC_VER)
44 #define MDNS_EXPORT __declspec(dllexport) extern
45 #else
46 #define MDNS_EXPORT extern
47 #endif
48 
49 struct mdns_ctx;
50 
51 #define MDNS_PORT        5353
52 #define MDNS_ADDR_IPV4   "224.0.0.251"
53 #define MDNS_ADDR_IPV6   "FF02::FB"
54 
55 #define GET_RCODE(x)    (x&0x000f)
56 #define SET_RCODE(x,c)  (x|(c&0x000f))
57 
58 #define GET_OPCODE(x)   (x&0x7800)
59 #define SET_OPCODE(x,c) (x|(c&0x7800))
60 
61 enum mdns_hdr_flag {
62        FLAG_QR = 1 << 15, // Question/Response
63        FLAG_AA = 1 << 10, // Authoritative Answer
64        FLAG_TC = 1 <<  9, // Truncated Response
65        FLAG_RD = 1 <<  8, // Recursion Desired
66        FLAG_RA = 1 <<  7, // Recursion Available
67        FLAG_Z  = 1 <<  6, // Reserved
68        FLAG_AD = 1 <<  5, // Authentic Data
69        FLAG_CD = 1 <<  4, // Checking Disabled
70 };
71 
72 struct mdns_hdr {
73         uint16_t id;
74         uint16_t flags;
75         uint16_t num_qn;
76         uint16_t num_ans_rr;
77         uint16_t num_auth_rr;
78         uint16_t num_add_rr;
79 };
80 
81 enum mdns_announce_type {
82     MDNS_ANNOUNCE_INITIAL,  // An initial announce needs to be sent
83     MDNS_ANNOUNCE_RESPONSE, // The application needs to respond to an MDNS question
84     MDNS_ANNOUNCE_GOODBYE,  // A goodbye packet needs to be sent
85 };
86 
87 typedef void (*mdns_listen_callback)(void*, int, const struct rr_entry *);
88 
89 /**
90  * @brief mdns_announce_callback Will be invoked for each received question
91  *
92  * @param cookie The pointer provided as last parameter to mdns_serve
93  * @param addr The address for which a probe was received
94  * @param service The service being probed or NULL when an initial discovery is requested
95  * @param type The type of announce that's expected from the application
96  *
97  * It is the application responsibility to filter which service it should respond
98  * to.
99  * This callback will be invoked with a NULL service upon startup so that the
100  * application can send a unsolicited announce. If there are more than a single
101  * network interface, this callback might be invoked multiple times for the same
102  * service, so that the application can announce itself as it sees fit (for
103  * instance it can announce both an A and AAAA records)
104  * This callback will also be invoked with a non-NULL service and
105  * MDNS_ANNOUNCE_INITIAL if the requests it through mdns_request_initial_announce
106  * In this case the application is responsible for knowing which service needs
107  * to be announced and announce it accordingly.
108  */
109 typedef void (*mdns_announce_callback)(void* cookie,
110                                        const struct sockaddr *addr,
111                                        const char* service,
112                                        enum mdns_announce_type type );
113 
114 /**
115  * \return true if the listener should be stopped
116  */
117 typedef bool (*mdns_stop_func)(void*);
118 
119 /**
120  * @brief Allocates and initialize a new mdns context
121  *
122  * @param ctx Returns the allocated context for the library [OUT]
123  * @param addr Protocol specific address to listen to, or NULL to use both IPv4 and IPv6
124  * @param port Port to listen on
125  *
126  * @see use mdns_destroy() to clean
127  *
128  * @return 0 if success, negative in other cases
129  */
130 MDNS_EXPORT int mdns_init(struct mdns_ctx **ctx, const char *addr, unsigned short port);
131 
132 /**
133  * @brief Destroy an mdns context
134  *
135  * @param ctx The context created by mdns_init()
136  *
137  * @return 0 if success, negative in other cases
138  */
139 MDNS_EXPORT int mdns_destroy(struct mdns_ctx *ctx);
140 
141 
142 /**
143  * @brief Send the entries on the network
144  *
145  * @param ctx A mdns context created by mdns_init()
146  * @param hdr A mdns_hdr header
147  * @param entries The entries to send
148  *
149  * @return 0 if successful, negative in other cases
150  */
151 MDNS_EXPORT int mdns_entries_send(const struct mdns_ctx *ctx, const struct mdns_hdr *hdr, const struct rr_entry *entries);
152 
153 /**
154  * @brief Print in human form an entry to debug
155  *
156  * @param entry The entry one wants to debug
157  */
158 MDNS_EXPORT void mdns_entries_print(const struct rr_entry *);
159 
160 /**
161  * @brief Wrapper around strerror to get strings from errors
162  *
163  * @param error The error number
164  * @param buf The buffer where the string can be written
165  * @param n The maximum of characters that can be written inside buf
166  *
167  * @return 0 if success, negative in other cases
168  */
169 MDNS_EXPORT int mdns_strerror(int error, char *buf, size_t n);
170 
171 /**
172  * @brief The main listening function for mDNS
173  *
174  * @param ctx A mdns context created by mdns_init()
175  * @param names The list of names of the services you are looking for
176  * @param nb_names The number of names in names list
177  * @param type The type of Record you want \see rr_type
178  * @param interval The refreshing interval to send a probe request (in seconds)
179  * @param stop The stop function to stop the discovery
180  * @param callback The callback function to receive the entries
181  * @param p_cookie user data for the callback
182  *
183  * @return 0 if success, negative in other cases
184  */
185 MDNS_EXPORT int mdns_listen(const struct mdns_ctx *ctx, const char *const names[],
186                        unsigned int nb_names, enum rr_type type,
187                        unsigned int interval, mdns_stop_func stop,
188                        mdns_listen_callback callback, void *p_cookie);
189 
190 /**
191  * @brief Announce a new name to serve
192  *
193  * @param ctx A mdns context created by mdns_init()
194  * @param type The type of Record you want \see rr_type
195  * @param callback The callback function to send the entries
196  * @param p_cookie user data for the callback
197  *
198  * @return 0 if success, negative in other cases
199  */
200 MDNS_EXPORT int mdns_announce(struct mdns_ctx *ctx, enum rr_type type,
201         mdns_announce_callback callback, void *p_cookie);
202 
203 /**
204  * @brief The main serving function for mDNS
205  * mdns_announce() must be called before for each service you want to announce.
206  *
207  * @param ctx A mdns context created by mdns_init()
208  * @param stop The stop function to stop the discovery
209  * @param p_cookie user data for the callback
210  *
211  * @return 0 if success, negative in other cases
212  */
213 
214 MDNS_EXPORT int mdns_serve(struct mdns_ctx *ctx, mdns_stop_func stop, void *p_cookie);
215 
216 /**
217  * @brief mdns_request_initial_announce Request an initial announce for the provided service
218  * @param ctx A mdns context created by mdns_init()
219  * @param service
220  */
221 MDNS_EXPORT void mdns_request_initial_announce(struct mdns_ctx *ctx, const char* service);
222 
223 # ifdef __cplusplus
224 }
225 # endif
226 
227 #endif /* MICRODNS_MDNS_H */
228