*/
static struct IPCache *cache_tail;
+/**
+ * Pipe for asynchronously notifying about resolve result
+ */
+static struct GNUNET_DISK_PipeHandle *resolve_result_pipe;
+
+/**
+ * Task for reading from resolve_result_pipe
+ */
+static struct GNUNET_SCHEDULER_Task *resolve_result_pipe_task;
+
#if HAVE_GETNAMEINFO
/**
static void
get_ip_as_string (struct GNUNET_SERVICE_Client *client,
int af,
- const void *ip)
+ const void *ip,
+ uint32_t request_id)
{
struct IPCache *pos;
struct IPCache *next;
struct GNUNET_TIME_Absolute now;
struct GNUNET_MQ_Envelope *env;
struct GNUNET_MQ_Handle *mq;
- struct GNUNET_MessageHeader *msg;
+ struct GNUNET_RESOLVER_ResponseMessage *msg;
size_t ip_len;
struct in6_addr ix;
size_t alen;
env = GNUNET_MQ_msg_extra (msg,
alen,
GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ msg->id = request_id;
GNUNET_memcpy (&msg[1],
pos->addr,
alen);
GNUNET_MQ_send (mq,
env);
+ // send end message
env = GNUNET_MQ_msg (msg,
GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ msg->id = request_id;
GNUNET_MQ_notify_sent (env,
¬ify_service_client_done,
client);
}
-#if HAVE_GETADDRINFO
+#if HAVE_GETADDRINFO_A
+struct AsyncCls
+{
+ struct gaicb *host;
+ struct sigevent *sig;
+ struct GNUNET_MQ_Handle *mq;
+ uint32_t request_id;
+};
+
+
+static void
+resolve_result_pipe_cb (void *cls)
+{
+ struct AsyncCls *async_cls;
+ struct gaicb *host;
+ struct GNUNET_RESOLVER_ResponseMessage *msg;
+ struct GNUNET_MQ_Envelope *env;
+
+ GNUNET_DISK_file_read (GNUNET_DISK_pipe_handle (resolve_result_pipe,
+ GNUNET_DISK_PIPE_END_READ),
+ &async_cls,
+ sizeof (struct AsyncCls *));
+ resolve_result_pipe_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_DISK_pipe_handle (resolve_result_pipe,
+ GNUNET_DISK_PIPE_END_READ),
+ &resolve_result_pipe_cb,
+ NULL);
+ host = async_cls->host;
+ for (struct addrinfo *pos = host->ar_result; pos != NULL; pos = pos->ai_next)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Lookup result for hostname %s: %s (request ID %u)\n",
+ host->ar_name,
+ GNUNET_a2s (pos->ai_addr, pos->ai_addrlen),
+ async_cls->request_id);
+ switch (pos->ai_family)
+ {
+ case AF_INET:
+ env = GNUNET_MQ_msg_extra (msg,
+ sizeof (struct in_addr),
+ GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ msg->id = async_cls->request_id;
+ GNUNET_memcpy (&msg[1],
+ &((struct sockaddr_in*) pos->ai_addr)->sin_addr,
+ sizeof (struct in_addr));
+ GNUNET_MQ_send (async_cls->mq,
+ env);
+ break;
+ case AF_INET6:
+ env = GNUNET_MQ_msg_extra (msg,
+ sizeof (struct in6_addr),
+ GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ msg->id = async_cls->request_id;
+ GNUNET_memcpy (&msg[1],
+ &((struct sockaddr_in6*) pos->ai_addr)->sin6_addr,
+ sizeof (struct in6_addr));
+ GNUNET_MQ_send (async_cls->mq,
+ env);
+ break;
+ default:
+ /* unsupported, skip */
+ break;
+ }
+ }
+ // send end message
+ env = GNUNET_MQ_msg (msg,
+ GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ msg->id = async_cls->request_id;
+ GNUNET_MQ_send (async_cls->mq,
+ env);
+ freeaddrinfo (host->ar_result);
+ GNUNET_free ((struct gaicb *)host->ar_request); // free hints
+ GNUNET_free (host);
+ GNUNET_free (async_cls->sig);
+ GNUNET_free (async_cls);
+}
+
+
+static void
+handle_async_result (union sigval val)
+{
+ GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (resolve_result_pipe,
+ GNUNET_DISK_PIPE_END_WRITE),
+ &val.sival_ptr,
+ sizeof (val.sival_ptr));
+}
+
+
+static int
+getaddrinfo_a_resolve (struct GNUNET_MQ_Handle *mq,
+ const char *hostname,
+ int af,
+ uint32_t request_id)
+{
+ int ret;
+ struct gaicb *host;
+ struct addrinfo *hints;
+ struct sigevent *sig;
+ struct AsyncCls *async_cls;
+
+ host = GNUNET_new (struct gaicb);
+ hints = GNUNET_new (struct addrinfo);
+ sig = GNUNET_new (struct sigevent);
+ async_cls = GNUNET_new (struct AsyncCls);
+ memset (hints,
+ 0,
+ sizeof (struct addrinfo));
+ memset (sig,
+ 0,
+ sizeof (struct sigevent));
+ hints->ai_family = af;
+ hints->ai_socktype = SOCK_STREAM; /* go for TCP */
+ host->ar_name = hostname;
+ host->ar_service = NULL;
+ host->ar_request = hints;
+ host->ar_result = NULL;
+ sig->sigev_notify = SIGEV_THREAD;
+ sig->sigev_value.sival_ptr = async_cls;
+ sig->sigev_notify_function = &handle_async_result;
+ async_cls->host = host;
+ async_cls->sig = sig;
+ async_cls->mq = mq;
+ async_cls->request_id = request_id;
+ ret = getaddrinfo_a (GAI_NOWAIT,
+ &host,
+ 1,
+ sig);
+ if (0 != ret)
+ return GNUNET_SYSERR;
+ return GNUNET_OK;
+}
+
+
+#elif HAVE_GETADDRINFO
static int
getaddrinfo_resolve (struct GNUNET_MQ_Handle *mq,
const char *hostname,
- int af)
+ int af,
+ uint32_t request_id)
{
int s;
struct addrinfo hints;
struct addrinfo *result;
struct addrinfo *pos;
- struct GNUNET_MessageHeader *msg;
+ struct GNUNET_RESOLVER_ResponseMessage *msg;
struct GNUNET_MQ_Envelope *env;
#ifdef WINDOWS
int ret2;
ret1 = getaddrinfo_resolve (mq,
hostname,
- AF_INET);
+ AF_INET,
+ request_id);
ret2 = getaddrinfo_resolve (mq,
hostname,
- AF_INET6);
+ AF_INET6,
+ request_id);
if ( (ret1 == GNUNET_OK) ||
(ret2 == GNUNET_OK) )
return GNUNET_OK;
env = GNUNET_MQ_msg_extra (msg,
sizeof (struct in_addr),
GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ msg->id = request_id;
GNUNET_memcpy (&msg[1],
&((struct sockaddr_in*) pos->ai_addr)->sin_addr,
sizeof (struct in_addr));
env = GNUNET_MQ_msg_extra (msg,
sizeof (struct in6_addr),
GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ msg->id = request_id;
GNUNET_memcpy (&msg[1],
&((struct sockaddr_in6*) pos->ai_addr)->sin6_addr,
sizeof (struct in6_addr));
static int
gethostbyname2_resolve (struct GNUNET_MQ_Handle *mq,
const char *hostname,
- int af)
+ int af,
+ uint32_t request_id)
{
struct hostent *hp;
int ret1;
int ret2;
struct GNUNET_MQ_Envelope *env;
- struct GNUNET_MessageHeader *msg;
+ struct GNUNET_RESOLVER_ResponseMessage *msg;
#ifdef WINDOWS
/* gethostbyname2() in plibc is a compat dummy that calls gethostbyname(). */
{
ret1 = gethostbyname2_resolve (mq,
hostname,
- AF_INET);
+ AF_INET,
+ request_id);
ret2 = gethostbyname2_resolve (mq,
hostname,
- AF_INET6);
+ AF_INET6,
+ request_id);
if ( (ret1 == GNUNET_OK) ||
(ret2 == GNUNET_OK) )
return GNUNET_OK;
env = GNUNET_MQ_msg_extra (msg,
hp->h_length,
GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ msg->id = request_id;
GNUNET_memcpy (&msg[1],
hp->h_addr_list[0],
hp->h_length);
env = GNUNET_MQ_msg_extra (msg,
hp->h_length,
GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ msg->id = request_id;
GNUNET_memcpy (&msg[1],
hp->h_addr_list[0],
hp->h_length);
static int
gethostbyname_resolve (struct GNUNET_MQ_Handle *mq,
- const char *hostname)
+ const char *hostname,
+ uint32_t request_id)
{
struct hostent *hp;
- struct GNUNET_MessageHeader *msg;
+ struct GNUNET_RESOLVER_ResponseMessage *msg;
struct GNUNET_MQ_Envelope *env;
hp = GETHOSTBYNAME (hostname);
env = GNUNET_MQ_msg_extra (msg,
hp->h_length,
GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ msg->id = request_id;
GNUNET_memcpy (&msg[1],
hp->h_addr_list[0],
hp->h_length);
static void
get_ip_from_hostname (struct GNUNET_SERVICE_Client *client,
const char *hostname,
- int af)
+ int af,
+ uint32_t request_id)
{
- int ret;
- struct GNUNET_MQ_Handle *mq;
struct GNUNET_MQ_Envelope *env;
- struct GNUNET_MessageHeader *msg;
+ struct GNUNET_RESOLVER_ResponseMessage *msg;
+ struct GNUNET_MQ_Handle *mq;
mq = GNUNET_SERVICE_client_get_mq (client);
- ret = GNUNET_NO;
-#if HAVE_GETADDRINFO
- if (ret == GNUNET_NO)
- ret = getaddrinfo_resolve (mq,
- hostname,
- af);
+#if HAVE_GETADDRINFO_A
+ getaddrinfo_a_resolve (mq,
+ hostname,
+ af,
+ request_id);
+ GNUNET_SERVICE_client_continue (client);
+ return;
+#elif HAVE_GETADDRINFO
+ getaddrinfo_resolve (mq,
+ hostname,
+ af,
+ request_id);
#elif HAVE_GETHOSTBYNAME2
- if (ret == GNUNET_NO)
- ret = gethostbyname2_resolve (mq,
- hostname,
- af);
+ gethostbyname2_resolve (mq,
+ hostname,
+ af,
+ request_id);
#elif HAVE_GETHOSTBYNAME
- if ( (ret == GNUNET_NO) &&
- ( (af == AF_UNSPEC) ||
+ if ( ( (af == AF_UNSPEC) ||
(af == PF_INET) ) )
gethostbyname_resolve (mq,
- hostname);
+ hostname,
+ request_id);
#endif
+ // send end message
env = GNUNET_MQ_msg (msg,
GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ msg->id = request_id;
GNUNET_MQ_notify_sent (env,
¬ify_service_client_done,
client);
const void *ip;
int direction;
int af;
+ uint32_t id;
direction = ntohl (msg->direction);
af = ntohl (msg->af);
+ id = ntohl (msg->id);
if (GNUNET_NO == direction)
{
/* IP from hostname */
const char *hostname;
hostname = (const char *) &msg[1];
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Resolver asked to look up `%s'.\n",
- hostname);
get_ip_from_hostname (client,
hostname,
- af);
+ af,
+ id);
return;
}
ip = &msg[1];
char buf[INET6_ADDRSTRLEN];
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Resolver asked to look up IP address `%s'.\n",
+ "Resolver asked to look up IP address `%s (request ID %u)'.\n",
inet_ntop (af,
ip,
buf,
- sizeof (buf)));
+ sizeof (buf)),
+ id);
}
#endif
get_ip_as_string (client,
af,
- ip);
+ ip,
+ id);
}
(void) cls;
(void) mq;
+#if HAVE_GETADDRINFO_A
+ resolve_result_pipe = GNUNET_DISK_pipe (GNUNET_NO,
+ GNUNET_NO,
+ GNUNET_NO,
+ GNUNET_NO);
+ GNUNET_assert (NULL != resolve_result_pipe);
+ resolve_result_pipe_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_DISK_pipe_handle (resolve_result_pipe,
+ GNUNET_DISK_PIPE_END_READ),
+ &resolve_result_pipe_cb,
+ NULL);
+#endif
return c;
}
{
(void) cls;
+#if HAVE_GETADDRINFO_A
+ if (NULL != resolve_result_pipe_task)
+ {
+ GNUNET_SCHEDULER_cancel (resolve_result_pipe_task);
+ resolve_result_pipe_task = NULL;
+ }
+ if (NULL != resolve_result_pipe)
+ {
+ GNUNET_DISK_pipe_close (resolve_result_pipe);
+ resolve_result_pipe = NULL;
+ }
+#endif
GNUNET_assert (c == internal_cls);
}
*/
static struct GNUNET_RESOLVER_RequestHandle *req_tail;
+/**
+ * ID of the last request we sent to the service
+ */
+static uint32_t last_request_id;
+
/**
* How long should we wait to reconnect?
*/
*/
int af;
+ /**
+ * Identifies the request. The response will contain this id.
+ */
+ uint32_t id;
+
/**
* Has this request been transmitted to the service?
* #GNUNET_YES if transmitted
GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
msg->direction = htonl (rh->direction);
msg->af = htonl (rh->af);
+ msg->id = htonl (rh->id);
GNUNET_memcpy (&msg[1],
&rh[1],
rh->data_len);
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Transmitting DNS resolution request to DNS service\n");
+ "Transmitting DNS resolution request (ID %u) to DNS service\n",
+ rh->id);
GNUNET_MQ_send (mq,
env);
rh->was_transmitted = GNUNET_YES;
*/
static int
check_response (void *cls,
- const struct GNUNET_MessageHeader *msg)
+ const struct GNUNET_RESOLVER_ResponseMessage *msg)
{
(void) cls;
(void) msg;
*/
static void
handle_response (void *cls,
- const struct GNUNET_MessageHeader *msg)
+ const struct GNUNET_RESOLVER_ResponseMessage *msg)
{
struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
uint16_t size;
char *nret;
+ uint32_t request_id = msg->id;
+
+ for (; rh != NULL; rh = rh->next)
+ {
+ if (rh->id == request_id)
+ break;
+ }
(void) cls;
if (NULL == rh)
reconnect ();
return;
}
- size = ntohs (msg->size);
- if (size == sizeof (struct GNUNET_MessageHeader))
+ size = ntohs (msg->header.size);
+ if (size == sizeof (struct GNUNET_RESOLVER_ResponseMessage))
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Received empty response from DNS service\n");
const char *hostname;
hostname = (const char *) &msg[1];
- if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
+ if (hostname[size - sizeof (struct GNUNET_RESOLVER_ResponseMessage) - 1] != '\0')
{
GNUNET_break (0);
if (GNUNET_SYSERR != rh->was_transmitted)
size_t ip_len;
ip = &msg[1];
- ip_len = size - sizeof (struct GNUNET_MessageHeader);
+ ip_len = size - sizeof (struct GNUNET_RESOLVER_ResponseMessage);
if (ip_len == sizeof (struct in_addr))
{
memset (&v4, 0, sizeof (v4));
struct GNUNET_MQ_MessageHandler handlers[] = {
GNUNET_MQ_hd_var_size (response,
GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE,
- struct GNUNET_MessageHeader,
+ struct GNUNET_RESOLVER_ResponseMessage,
NULL),
GNUNET_MQ_handler_end ()
};
hostname);
rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen);
rh->af = af;
+ rh->id = ++last_request_id;
rh->addr_callback = callback;
rh->cls = callback_cls;
GNUNET_memcpy (&rh[1],
rh->name_callback = callback;
rh->cls = cls;
rh->af = sa->sa_family;
+ rh->id = ++last_request_id;
rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
GNUNET_memcpy (&rh[1],
ip,