2 This file is part of GNUnet
3 Copyright (C) 2012, 2016 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU 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.
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.
18 * @brief API to access the DNS service.
19 * @author Christian Grothoff
22 #include "gnunet_dns_service.h"
27 * Handle to identify an individual DNS request.
29 struct GNUNET_DNS_RequestHandle
35 struct GNUNET_DNS_Handle *dh;
38 * Stored in network byte order (as for us, it is just a random number).
43 * Re-connect counter, to make sure we did not reconnect in the meantime.
53 struct GNUNET_DNS_Handle
57 * Connection to DNS service, or NULL.
59 struct GNUNET_MQ_Handle *mq;
62 * Configuration to use.
64 const struct GNUNET_CONFIGURATION_Handle *cfg;
67 * Function to call to get replies.
69 GNUNET_DNS_RequestHandler rh;
77 * Task to reconnect to the service.
79 struct GNUNET_SCHEDULER_Task *reconnect_task;
82 * Re-connect counter, to make sure we did not reconnect in the meantime.
87 * Flags for events we care about.
89 enum GNUNET_DNS_Flags flags;
92 * Number of GNUNET_DNS_RequestHandles we have outstanding. Must be 0 before
93 * we can be disconnected.
95 unsigned int pending_requests;
100 * Reconnect to the DNS service.
102 * @param cls handle with the connection to connect
103 * @param tc scheduler context (unused)
106 reconnect (void *cls);
110 * Drop the existing connection and reconnect to the DNS service.
112 * @param dh handle with the connection
115 force_reconnect (struct GNUNET_DNS_Handle *dh)
119 GNUNET_MQ_destroy (dh->mq);
123 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
130 * Generic error handler, called with the appropriate error code and
131 * the same closure specified at the creation of the message queue.
132 * Not every message queue implementation supports an error handler.
134 * @param cls closure with the `struct GNUNET_DNS_Handle *`
135 * @param error error code
138 mq_error_handler (void *cls,
139 enum GNUNET_MQ_Error error)
141 struct GNUNET_DNS_Handle *dh = cls;
143 force_reconnect (dh);
149 * This receives packets from the DNS service and calls the application to
150 * check that the request is well-formed
152 * @param cls the struct GNUNET_DNS_Handle
153 * @param req message from the service (request)
156 check_request (void *cls,
157 const struct GNUNET_DNS_Request *req)
159 if (0 != ntohl (req->reserved))
162 return GNUNET_SYSERR;
169 * This receives packets from the DNS service and calls the application to
172 * @param cls the `struct GNUNET_DNS_Handle *`
173 * @param msg message from the service (request)
176 handle_request (void *cls,
177 const struct GNUNET_DNS_Request *req)
179 struct GNUNET_DNS_Handle *dh = cls;
180 size_t payload_length = ntohs (req->header.size) - sizeof (*req);
181 struct GNUNET_DNS_RequestHandle *rh;
183 rh = GNUNET_new (struct GNUNET_DNS_RequestHandle);
185 rh->request_id = req->request_id;
186 rh->generation = dh->generation;
187 dh->pending_requests++;
191 (const char*) &req[1]);
196 * Reconnect to the DNS service.
198 * @param cls handle with the connection to connect
201 reconnect (void *cls)
203 struct GNUNET_DNS_Handle *dh = cls;
204 struct GNUNET_MQ_MessageHandler handlers[] = {
205 GNUNET_MQ_hd_var_size (request,
206 GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST,
207 struct GNUNET_DNS_Request,
209 GNUNET_MQ_handler_end ()
211 struct GNUNET_MQ_Envelope *env;
212 struct GNUNET_DNS_Register *msg;
214 dh->reconnect_task = NULL;
215 dh->mq = GNUNET_CLIENT_connect (dh->cfg,
223 env = GNUNET_MQ_msg (msg,
224 GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT);
225 msg->flags = htonl (dh->flags);
226 GNUNET_MQ_send (dh->mq,
232 * If a GNUNET_DNS_RequestHandler calls this function, the request is
233 * given to other clients or the global DNS for resolution. Once a
234 * global response has been obtained, the request handler is AGAIN
235 * called to give it a chance to observe and modify the response after
236 * the "normal" resolution. It is not legal for the request handler
237 * to call this function if a response is already present.
239 * @param rh request that should now be forwarded
242 GNUNET_DNS_request_forward (struct GNUNET_DNS_RequestHandle *rh)
244 struct GNUNET_MQ_Envelope *env;
245 struct GNUNET_DNS_Response *resp;
247 GNUNET_assert (0 < rh->dh->pending_requests--);
248 if (rh->generation != rh->dh->generation)
253 env = GNUNET_MQ_msg (resp,
254 GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
255 resp->drop_flag = htonl (1);
256 resp->request_id = rh->request_id;
257 GNUNET_MQ_send (rh->dh->mq,
264 * If a GNUNET_DNS_RequestHandler calls this function, the request is
265 * to be dropped and no response should be generated.
267 * @param rh request that should now be dropped
270 GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh)
272 struct GNUNET_MQ_Envelope *env;
273 struct GNUNET_DNS_Response *resp;
275 GNUNET_assert (0 < rh->dh->pending_requests--);
276 if (rh->generation != rh->dh->generation)
281 env = GNUNET_MQ_msg (resp,
282 GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
283 resp->request_id = rh->request_id;
284 resp->drop_flag = htonl (0);
285 GNUNET_MQ_send (rh->dh->mq,
292 * If a GNUNET_DNS_RequestHandler calls this function, the request is
293 * supposed to be answered with the data provided to this call (with
294 * the modifications the function might have made).
296 * @param rh request that should now be answered
297 * @param reply_length size of @a reply (uint16_t to force sane size)
298 * @param reply reply data
301 GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh,
302 uint16_t reply_length,
305 struct GNUNET_MQ_Envelope *env;
306 struct GNUNET_DNS_Response *resp;
308 GNUNET_assert (0 < rh->dh->pending_requests--);
309 if (rh->generation != rh->dh->generation)
314 if (reply_length + sizeof (struct GNUNET_DNS_Response)
315 >= GNUNET_MAX_MESSAGE_SIZE)
321 env = GNUNET_MQ_msg_extra (resp,
323 GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
324 resp->drop_flag = htonl (2);
325 resp->request_id = rh->request_id;
326 GNUNET_memcpy (&resp[1],
329 GNUNET_MQ_send (rh->dh->mq,
336 * Connect to the service-dns
338 * @param cfg configuration to use
339 * @param flags when to call @a rh
340 * @param rh function to call with DNS requests
341 * @param rh_cls closure to pass to @a rh
344 struct GNUNET_DNS_Handle *
345 GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
346 enum GNUNET_DNS_Flags flags,
347 GNUNET_DNS_RequestHandler rh,
350 struct GNUNET_DNS_Handle *dh;
352 dh = GNUNET_new (struct GNUNET_DNS_Handle);
357 dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh);
363 * Disconnect from the DNS service.
365 * @param dh DNS handle
368 GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *dh)
372 GNUNET_MQ_destroy (dh->mq);
375 if (NULL != dh->reconnect_task)
377 GNUNET_SCHEDULER_cancel (dh->reconnect_task);
378 dh->reconnect_task = NULL;
380 /* make sure client has no pending requests left over! */
381 GNUNET_break (0 == dh->pending_requests);
385 /* end of dns_api.c */