/*
This file is part of GNUnet
- Copyright (C) 2012 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2012, 2016 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
#include "dns.h"
-/**
- * Reply to send to service.
- */
-struct ReplyQueueEntry
-{
- /**
- * Kept in DLL.
- */
- struct ReplyQueueEntry *next;
-
- /**
- * Kept in DLL.
- */
- struct ReplyQueueEntry *prev;
-
- /**
- * Message to transmit, allocated at the end of this struct.
- */
- const struct GNUNET_MessageHeader *msg;
-
-};
-
-
/**
* Handle to identify an individual DNS request.
*/
/**
* Connection to DNS service, or NULL.
*/
- struct GNUNET_CLIENT_Connection *dns_connection;
-
- /**
- * Handle to active transmission request, or NULL.
- */
- struct GNUNET_CLIENT_TransmitHandle *dns_transmit_handle;
+ struct GNUNET_MQ_Handle *mq;
/**
* Configuration to use.
GNUNET_DNS_RequestHandler rh;
/**
- * Closure for 'rh'.
+ * Closure for @e rh.
*/
void *rh_cls;
- /**
- * Head of replies to transmit.
- */
- struct ReplyQueueEntry *rq_head;
-
- /**
- * Tail of replies to transmit.
- */
- struct ReplyQueueEntry *rq_tail;
-
/**
* Task to reconnect to the service.
*/
- struct GNUNET_SCHEDULER_Task * reconnect_task;
+ struct GNUNET_SCHEDULER_Task *reconnect_task;
/**
* Re-connect counter, to make sure we did not reconnect in the meantime.
*/
enum GNUNET_DNS_Flags flags;
- /**
- * Did we start the receive loop yet?
- */
- int in_receive;
-
/**
* Number of GNUNET_DNS_RequestHandles we have outstanding. Must be 0 before
* we can be disconnected.
/**
- * Add the given reply to our transmission queue and trigger sending if needed.
+ * Reconnect to the DNS service.
+ *
+ * @param cls handle with the connection to connect
+ * @param tc scheduler context (unused)
+ */
+static void
+reconnect (void *cls);
+
+
+/**
+ * Drop the existing connection and reconnect to the DNS service.
*
* @param dh handle with the connection
- * @param qe reply to queue
*/
static void
-queue_reply (struct GNUNET_DNS_Handle *dh,
- struct ReplyQueueEntry *qe);
+force_reconnect (struct GNUNET_DNS_Handle *dh)
+{
+ if (NULL != dh->mq)
+ {
+ GNUNET_MQ_destroy (dh->mq);
+ dh->mq = NULL;
+ }
+ dh->reconnect_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+ &reconnect,
+ dh);
+}
/**
- * Reconnect to the DNS service.
+ * Generic error handler, called with the appropriate error code and
+ * the same closure specified at the creation of the message queue.
+ * Not every message queue implementation supports an error handler.
*
- * @param cls handle with the connection to connect
- * @param tc scheduler context (unused)
+ * @param cls closure with the `struct GNUNET_DNS_Handle *`
+ * @param error error code
*/
static void
-reconnect (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
+mq_error_handler (void *cls,
+ enum GNUNET_MQ_Error error)
{
struct GNUNET_DNS_Handle *dh = cls;
- struct ReplyQueueEntry *qe;
- struct GNUNET_DNS_Register *msg;
- dh->reconnect_task = NULL;
- dh->dns_connection = GNUNET_CLIENT_connect ("dns", dh->cfg);
- if (NULL == dh->dns_connection)
- return;
- dh->generation++;
- qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) +
- sizeof (struct GNUNET_DNS_Register));
- msg = (struct GNUNET_DNS_Register*) &qe[1];
- qe->msg = &msg->header;
- msg->header.size = htons (sizeof (struct GNUNET_DNS_Register));
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT);
- msg->flags = htonl (dh->flags);
- queue_reply (dh, qe);
+ force_reconnect (dh);
}
+
/**
- * Disconnect from the DNS service.
+ * This receives packets from the DNS service and calls the application to
+ * check that the request is well-formed
*
- * @param dh handle with the connection to disconnect
+ * @param cls the struct GNUNET_DNS_Handle
+ * @param req message from the service (request)
*/
-static void
-disconnect (struct GNUNET_DNS_Handle *dh)
+static int
+check_request (void *cls,
+ const struct GNUNET_DNS_Request *req)
{
- struct ReplyQueueEntry *qe;
-
- if (NULL != dh->dns_transmit_handle)
- {
- GNUNET_CLIENT_notify_transmit_ready_cancel (dh->dns_transmit_handle);
- dh->dns_transmit_handle = NULL;
- }
- if (NULL != dh->dns_connection)
- {
- GNUNET_CLIENT_disconnect (dh->dns_connection);
- dh->dns_connection = NULL;
- }
- while (NULL != (qe = dh->rq_head))
+ if (0 != ntohl (req->reserved))
{
- GNUNET_CONTAINER_DLL_remove (dh->rq_head,
- dh->rq_tail,
- qe);
- GNUNET_free (qe);
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
}
- dh->in_receive = GNUNET_NO;
+ return GNUNET_OK;
}
* This receives packets from the DNS service and calls the application to
* handle it.
*
- * @param cls the struct GNUNET_DNS_Handle
+ * @param cls the `struct GNUNET_DNS_Handle *`
* @param msg message from the service (request)
*/
static void
-request_handler (void *cls,
- const struct GNUNET_MessageHeader *msg)
+handle_request (void *cls,
+ const struct GNUNET_DNS_Request *req)
{
struct GNUNET_DNS_Handle *dh = cls;
- const struct GNUNET_DNS_Request *req;
+ size_t payload_length = ntohs (req->header.size) - sizeof (*req);
struct GNUNET_DNS_RequestHandle *rh;
- size_t payload_length;
- /* the service disconnected, reconnect after short wait */
- if (msg == NULL)
- {
- disconnect (dh);
- dh->reconnect_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
- &reconnect, dh);
- return;
- }
- if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST) ||
- (ntohs (msg->size) < sizeof (struct GNUNET_DNS_Request)) )
- {
- /* the service did something strange, reconnect immediately */
- GNUNET_break (0);
- disconnect (dh);
- dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh);
- return;
- }
- req = (const struct GNUNET_DNS_Request *) msg;
- GNUNET_break (ntohl (req->reserved) == 0);
- payload_length = ntohs (req->header.size) - sizeof (struct GNUNET_DNS_Request);
- GNUNET_CLIENT_receive (dh->dns_connection,
- &request_handler, dh,
- GNUNET_TIME_UNIT_FOREVER_REL);
-
- /* finally, pass request to callback for answers */
rh = GNUNET_new (struct GNUNET_DNS_RequestHandle);
rh->dh =dh;
rh->request_id = req->request_id;
/**
- * Callback called by notify_transmit_ready; sends DNS replies
- * to the DNS service.
+ * Reconnect to the DNS service.
*
- * @param cls the struct GNUNET_DNS_Handle
- * @param size number of bytes available in buf
- * @param buf where to copy the message for transmission
- * @return number of bytes copied to buf
+ * @param cls handle with the connection to connect
*/
-static size_t
-send_response (void *cls, size_t size, void *buf)
+static void
+reconnect (void *cls)
{
+ GNUNET_MQ_hd_var_size (request,
+ GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST,
+ struct GNUNET_DNS_Request);
struct GNUNET_DNS_Handle *dh = cls;
- struct ReplyQueueEntry *qe;
- size_t len;
-
- dh->dns_transmit_handle = NULL;
- if (NULL == buf)
- {
- disconnect (dh);
- dh->reconnect_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
- &reconnect, dh);
- return 0;
- }
- qe = dh->rq_head;
- if (NULL == qe)
- return 0;
- len = ntohs (qe->msg->size);
- if (len > size)
- {
- dh->dns_transmit_handle =
- GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection,
- len,
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_NO,
- &send_response, dh);
- return 0;
- }
- memcpy (buf, qe->msg, len);
- GNUNET_CONTAINER_DLL_remove (dh->rq_head,
- dh->rq_tail,
- qe);
- GNUNET_free (qe);
- if (GNUNET_NO == dh->in_receive)
- {
- dh->in_receive = GNUNET_YES;
- GNUNET_CLIENT_receive (dh->dns_connection,
- &request_handler, dh,
- GNUNET_TIME_UNIT_FOREVER_REL);
- }
- if (NULL != (qe = dh->rq_head))
- {
- dh->dns_transmit_handle =
- GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection,
- ntohs (qe->msg->size),
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_NO,
- &send_response, dh);
- }
- return len;
-}
-
+ struct GNUNET_MQ_MessageHandler handlers[] = {
+ make_request_handler (dh),
+ GNUNET_MQ_handler_end ()
+ };
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_DNS_Register *msg;
-/**
- * Add the given reply to our transmission queue and trigger sending if needed.
- *
- * @param dh handle with the connection
- * @param qe reply to queue
- */
-static void
-queue_reply (struct GNUNET_DNS_Handle *dh,
- struct ReplyQueueEntry *qe)
-{
- if (NULL == dh->dns_connection)
- {
- GNUNET_free (qe);
- return;
- }
- GNUNET_CONTAINER_DLL_insert_tail (dh->rq_head,
- dh->rq_tail,
- qe);
- if (NULL != dh->dns_transmit_handle)
+ dh->reconnect_task = NULL;
+ dh->mq = GNUNET_CLIENT_connecT (dh->cfg,
+ "dns",
+ handlers,
+ &mq_error_handler,
+ dh);
+ if (NULL == dh->mq)
return;
- /* trigger sending */
- dh->dns_transmit_handle =
- GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection,
- ntohs (dh->rq_head->msg->size),
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_NO,
- &send_response, dh);
+ dh->generation++;
+ env = GNUNET_MQ_msg (msg,
+ GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT);
+ msg->flags = htonl (dh->flags);
+ GNUNET_MQ_send (dh->mq,
+ env);
}
void
GNUNET_DNS_request_forward (struct GNUNET_DNS_RequestHandle *rh)
{
- struct ReplyQueueEntry *qe;
+ struct GNUNET_MQ_Envelope *env;
struct GNUNET_DNS_Response *resp;
GNUNET_assert (0 < rh->dh->pending_requests--);
GNUNET_free (rh);
return;
}
- qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) +
- sizeof (struct GNUNET_DNS_Response));
- resp = (struct GNUNET_DNS_Response*) &qe[1];
- qe->msg = &resp->header;
- resp->header.size = htons (sizeof (struct GNUNET_DNS_Response));
- resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
+ env = GNUNET_MQ_msg (resp,
+ GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
resp->drop_flag = htonl (1);
resp->request_id = rh->request_id;
- queue_reply (rh->dh, qe);
+ GNUNET_MQ_send (rh->dh->mq,
+ env);
GNUNET_free (rh);
}
void
GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh)
{
- struct ReplyQueueEntry *qe;
+ struct GNUNET_MQ_Envelope *env;
struct GNUNET_DNS_Response *resp;
GNUNET_assert (0 < rh->dh->pending_requests--);
GNUNET_free (rh);
return;
}
- qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) +
- sizeof (struct GNUNET_DNS_Response));
- resp = (struct GNUNET_DNS_Response*) &qe[1];
- qe->msg = &resp->header;
- resp->header.size = htons (sizeof (struct GNUNET_DNS_Response));
- resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
+ env = GNUNET_MQ_msg (resp,
+ GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
resp->request_id = rh->request_id;
resp->drop_flag = htonl (0);
- queue_reply (rh->dh, qe);
+ GNUNET_MQ_send (rh->dh->mq,
+ env);
GNUNET_free (rh);
}
* the modifications the function might have made).
*
* @param rh request that should now be answered
- * @param reply_length size of reply (uint16_t to force sane size)
+ * @param reply_length size of @a reply (uint16_t to force sane size)
* @param reply reply data
*/
void
-GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh,
+GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh,
uint16_t reply_length,
const char *reply)
{
- struct ReplyQueueEntry *qe;
+ struct GNUNET_MQ_Envelope *env;
struct GNUNET_DNS_Response *resp;
GNUNET_assert (0 < rh->dh->pending_requests--);
GNUNET_free (rh);
return;
}
- if (reply_length + sizeof (struct GNUNET_DNS_Response) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ if (reply_length + sizeof (struct GNUNET_DNS_Response)
+ >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
{
GNUNET_break (0);
GNUNET_free (rh);
return;
}
- qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) +
- sizeof (struct GNUNET_DNS_Response) + reply_length);
- resp = (struct GNUNET_DNS_Response*) &qe[1];
- qe->msg = &resp->header;
- resp->header.size = htons (sizeof (struct GNUNET_DNS_Response) + reply_length);
- resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
+ env = GNUNET_MQ_msg_extra (resp,
+ reply_length,
+ GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
resp->drop_flag = htonl (2);
resp->request_id = rh->request_id;
- memcpy (&resp[1], reply, reply_length);
- queue_reply (rh->dh, qe);
+ memcpy (&resp[1],
+ reply,
+ reply_length);
+ GNUNET_MQ_send (rh->dh->mq,
+ env);
GNUNET_free (rh);
}
* Connect to the service-dns
*
* @param cfg configuration to use
- * @param flags when to call rh
+ * @param flags when to call @a rh
* @param rh function to call with DNS requests
- * @param rh_cls closure to pass to rh
+ * @param rh_cls closure to pass to @a rh
* @return DNS handle
*/
struct GNUNET_DNS_Handle *
void
GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *dh)
{
+ if (NULL != dh->mq)
+ {
+ GNUNET_MQ_destroy (dh->mq);
+ dh->mq = NULL;
+ }
if (NULL != dh->reconnect_task)
{
GNUNET_SCHEDULER_cancel (dh->reconnect_task);
dh->reconnect_task = NULL;
}
- disconnect (dh);
/* make sure client has no pending requests left over! */
- GNUNET_assert (0 == dh->pending_requests);
+ GNUNET_break (0 == dh->pending_requests);
GNUNET_free (dh);
}
-/* end of dns_api_new.c */
+/* end of dns_api.c */