aboutsummaryrefslogtreecommitdiff
path: root/src/service/dns/dns_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/dns/dns_api.c')
-rw-r--r--src/service/dns/dns_api.c381
1 files changed, 381 insertions, 0 deletions
diff --git a/src/service/dns/dns_api.c b/src/service/dns/dns_api.c
new file mode 100644
index 000000000..b0bbb894f
--- /dev/null
+++ b/src/service/dns/dns_api.c
@@ -0,0 +1,381 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file dns/dns_api.c
23 * @brief API to access the DNS service.
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_dns_service.h"
28#include "dns.h"
29
30
31/**
32 * Handle to identify an individual DNS request.
33 */
34struct GNUNET_DNS_RequestHandle
35{
36 /**
37 * Handle to DNS API.
38 */
39 struct GNUNET_DNS_Handle *dh;
40
41 /**
42 * Stored in network byte order (as for us, it is just a random number).
43 */
44 uint64_t request_id;
45
46 /**
47 * Re-connect counter, to make sure we did not reconnect in the meantime.
48 */
49 uint32_t generation;
50};
51
52
53/**
54 * DNS handle
55 */
56struct GNUNET_DNS_Handle
57{
58 /**
59 * Connection to DNS service, or NULL.
60 */
61 struct GNUNET_MQ_Handle *mq;
62
63 /**
64 * Configuration to use.
65 */
66 const struct GNUNET_CONFIGURATION_Handle *cfg;
67
68 /**
69 * Function to call to get replies.
70 */
71 GNUNET_DNS_RequestHandler rh;
72
73 /**
74 * Closure for @e rh.
75 */
76 void *rh_cls;
77
78 /**
79 * Task to reconnect to the service.
80 */
81 struct GNUNET_SCHEDULER_Task *reconnect_task;
82
83 /**
84 * Re-connect counter, to make sure we did not reconnect in the meantime.
85 */
86 uint32_t generation;
87
88 /**
89 * Flags for events we care about.
90 */
91 enum GNUNET_DNS_Flags flags;
92
93 /**
94 * Number of GNUNET_DNS_RequestHandles we have outstanding. Must be 0 before
95 * we can be disconnected.
96 */
97 unsigned int pending_requests;
98};
99
100
101/**
102 * Reconnect to the DNS service.
103 *
104 * @param cls handle with the connection to connect
105 */
106static void
107reconnect (void *cls);
108
109
110/**
111 * Drop the existing connection and reconnect to the DNS service.
112 *
113 * @param dh handle with the connection
114 */
115static void
116force_reconnect (struct GNUNET_DNS_Handle *dh)
117{
118 if (NULL != dh->mq)
119 {
120 GNUNET_MQ_destroy (dh->mq);
121 dh->mq = NULL;
122 }
123 dh->reconnect_task =
124 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
125 &reconnect,
126 dh);
127}
128
129
130/**
131 * Generic error handler, called with the appropriate error code and
132 * the same closure specified at the creation of the message queue.
133 * Not every message queue implementation supports an error handler.
134 *
135 * @param cls closure with the `struct GNUNET_DNS_Handle *`
136 * @param error error code
137 */
138static void
139mq_error_handler (void *cls,
140 enum GNUNET_MQ_Error error)
141{
142 struct GNUNET_DNS_Handle *dh = cls;
143
144 force_reconnect (dh);
145}
146
147
148/**
149 * This receives packets from the DNS service and calls the application to
150 * check that the request is well-formed
151 *
152 * @param cls the struct GNUNET_DNS_Handle
153 * @param req message from the service (request)
154 */
155static int
156check_request (void *cls,
157 const struct GNUNET_DNS_Request *req)
158{
159 if (0 != ntohl (req->reserved))
160 {
161 GNUNET_break (0);
162 return GNUNET_SYSERR;
163 }
164 return GNUNET_OK;
165}
166
167
168/**
169 * This receives packets from the DNS service and calls the application to
170 * handle it.
171 *
172 * @param cls the `struct GNUNET_DNS_Handle *`
173 * @param req message from the service (request)
174 */
175static void
176handle_request (void *cls,
177 const struct GNUNET_DNS_Request *req)
178{
179 struct GNUNET_DNS_Handle *dh = cls;
180 size_t payload_length = ntohs (req->header.size) - sizeof(*req);
181 struct GNUNET_DNS_RequestHandle *rh;
182
183 rh = GNUNET_new (struct GNUNET_DNS_RequestHandle);
184 rh->dh = dh;
185 rh->request_id = req->request_id;
186 rh->generation = dh->generation;
187 dh->pending_requests++;
188 dh->rh (dh->rh_cls,
189 rh,
190 payload_length,
191 (const char *) &req[1]);
192}
193
194
195static void
196reconnect (void *cls)
197{
198 struct GNUNET_DNS_Handle *dh = cls;
199 struct GNUNET_MQ_MessageHandler handlers[] = {
200 GNUNET_MQ_hd_var_size (request,
201 GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST,
202 struct GNUNET_DNS_Request,
203 dh),
204 GNUNET_MQ_handler_end ()
205 };
206 struct GNUNET_MQ_Envelope *env;
207 struct GNUNET_DNS_Register *msg;
208
209 dh->reconnect_task = NULL;
210 dh->mq = GNUNET_CLIENT_connect (dh->cfg,
211 "dns",
212 handlers,
213 &mq_error_handler,
214 dh);
215 if (NULL == dh->mq)
216 return;
217 dh->generation++;
218 env = GNUNET_MQ_msg (msg,
219 GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT);
220 msg->flags = htonl (dh->flags);
221 GNUNET_MQ_send (dh->mq,
222 env);
223}
224
225
226/**
227 * If a GNUNET_DNS_RequestHandler calls this function, the request is
228 * given to other clients or the global DNS for resolution. Once a
229 * global response has been obtained, the request handler is AGAIN
230 * called to give it a chance to observe and modify the response after
231 * the "normal" resolution. It is not legal for the request handler
232 * to call this function if a response is already present.
233 *
234 * @param rh request that should now be forwarded
235 */
236void
237GNUNET_DNS_request_forward (struct GNUNET_DNS_RequestHandle *rh)
238{
239 struct GNUNET_MQ_Envelope *env;
240 struct GNUNET_DNS_Response *resp;
241
242 GNUNET_assert (0 < rh->dh->pending_requests--);
243 if (rh->generation != rh->dh->generation)
244 {
245 GNUNET_free (rh);
246 return;
247 }
248 env = GNUNET_MQ_msg (resp,
249 GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
250 resp->drop_flag = htonl (1);
251 resp->request_id = rh->request_id;
252 GNUNET_MQ_send (rh->dh->mq,
253 env);
254 GNUNET_free (rh);
255}
256
257
258/**
259 * If a GNUNET_DNS_RequestHandler calls this function, the request is
260 * to be dropped and no response should be generated.
261 *
262 * @param rh request that should now be dropped
263 */
264void
265GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh)
266{
267 struct GNUNET_MQ_Envelope *env;
268 struct GNUNET_DNS_Response *resp;
269
270 GNUNET_assert (0 < rh->dh->pending_requests--);
271 if (rh->generation != rh->dh->generation)
272 {
273 GNUNET_free (rh);
274 return;
275 }
276 env = GNUNET_MQ_msg (resp,
277 GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
278 resp->request_id = rh->request_id;
279 resp->drop_flag = htonl (0);
280 GNUNET_MQ_send (rh->dh->mq,
281 env);
282 GNUNET_free (rh);
283}
284
285
286/**
287 * If a GNUNET_DNS_RequestHandler calls this function, the request is
288 * supposed to be answered with the data provided to this call (with
289 * the modifications the function might have made).
290 *
291 * @param rh request that should now be answered
292 * @param reply_length size of @a reply (uint16_t to force sane size)
293 * @param reply reply data
294 */
295void
296GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh,
297 uint16_t reply_length,
298 const char *reply)
299{
300 struct GNUNET_MQ_Envelope *env;
301 struct GNUNET_DNS_Response *resp;
302
303 GNUNET_assert (0 < rh->dh->pending_requests--);
304 if (rh->generation != rh->dh->generation)
305 {
306 GNUNET_free (rh);
307 return;
308 }
309 if (reply_length + sizeof(struct GNUNET_DNS_Response)
310 >= GNUNET_MAX_MESSAGE_SIZE)
311 {
312 GNUNET_break (0);
313 GNUNET_free (rh);
314 return;
315 }
316 env = GNUNET_MQ_msg_extra (resp,
317 reply_length,
318 GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
319 resp->drop_flag = htonl (2);
320 resp->request_id = rh->request_id;
321 GNUNET_memcpy (&resp[1],
322 reply,
323 reply_length);
324 GNUNET_MQ_send (rh->dh->mq,
325 env);
326 GNUNET_free (rh);
327}
328
329
330/**
331 * Connect to the service-dns
332 *
333 * @param cfg configuration to use
334 * @param flags when to call @a rh
335 * @param rh function to call with DNS requests
336 * @param rh_cls closure to pass to @a rh
337 * @return DNS handle
338 */
339struct GNUNET_DNS_Handle *
340GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
341 enum GNUNET_DNS_Flags flags,
342 GNUNET_DNS_RequestHandler rh,
343 void *rh_cls)
344{
345 struct GNUNET_DNS_Handle *dh;
346
347 dh = GNUNET_new (struct GNUNET_DNS_Handle);
348 dh->cfg = cfg;
349 dh->flags = flags;
350 dh->rh = rh;
351 dh->rh_cls = rh_cls;
352 dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh);
353 return dh;
354}
355
356
357/**
358 * Disconnect from the DNS service.
359 *
360 * @param dh DNS handle
361 */
362void
363GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *dh)
364{
365 if (NULL != dh->mq)
366 {
367 GNUNET_MQ_destroy (dh->mq);
368 dh->mq = NULL;
369 }
370 if (NULL != dh->reconnect_task)
371 {
372 GNUNET_SCHEDULER_cancel (dh->reconnect_task);
373 dh->reconnect_task = NULL;
374 }
375 /* make sure client has no pending requests left over! */
376 GNUNET_break (0 == dh->pending_requests);
377 GNUNET_free (dh);
378}
379
380
381/* end of dns_api.c */