/*
This file is part of GNUnet.
Copyright (C) 2009-2018 GNUnet e.V.
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file util/resolver_api.c
* @brief resolver for writing a tool
* @author Christian Grothoff
*/
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_protocols.h"
#include "gnunet_resolver_service.h"
#include "resolver.h"
#define LOG(kind,...) GNUNET_log_from (kind, "util-resolver-api", __VA_ARGS__)
#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-resolver-api", syscall)
/**
* Maximum supported length for a hostname
*/
#define MAX_HOSTNAME 1024
/**
* Possible hostnames for "loopback".
*/
static const char *loopback[] = {
"localhost",
"ip6-localnet",
NULL
};
/**
* Configuration.
*/
static const struct GNUNET_CONFIGURATION_Handle *resolver_cfg;
/**
* Our connection to the resolver service, created on-demand, but then
* persists until error or shutdown.
*/
static struct GNUNET_MQ_Handle *mq;
/**
* Head of DLL of requests.
*/
static struct GNUNET_RESOLVER_RequestHandle *req_head;
/**
* Tail of DLL of requests.
*/
static struct GNUNET_RESOLVER_RequestHandle *req_tail;
/**
* How long should we wait to reconnect?
*/
static struct GNUNET_TIME_Relative backoff;
/**
* Task for reconnecting.
*/
static struct GNUNET_SCHEDULER_Task *r_task;
/**
* Task ID of shutdown task; only present while we have a
* connection to the resolver service.
*/
static struct GNUNET_SCHEDULER_Task *s_task;
/**
* Handle to a request given to the resolver. Can be used to cancel
* the request prior to the timeout or successful execution. Also
* used to track our internal state for the request.
*/
struct GNUNET_RESOLVER_RequestHandle
{
/**
* Next entry in DLL of requests.
*/
struct GNUNET_RESOLVER_RequestHandle *next;
/**
* Previous entry in DLL of requests.
*/
struct GNUNET_RESOLVER_RequestHandle *prev;
/**
* Callback if this is an name resolution request,
* otherwise NULL.
*/
GNUNET_RESOLVER_AddressCallback addr_callback;
/**
* Callback if this is a reverse lookup request,
* otherwise NULL.
*/
GNUNET_RESOLVER_HostnameCallback name_callback;
/**
* Closure for the callbacks.
*/
void *cls;
/**
* When should this request time out?
*/
struct GNUNET_TIME_Absolute timeout;
/**
* Task handle for making reply callbacks in numeric lookups
* asynchronous, and for timeout handling.
*/
struct GNUNET_SCHEDULER_Task *task;
/**
* Desired address family.
*/
int af;
/**
* Has this request been transmitted to the service?
* #GNUNET_YES if transmitted
* #GNUNET_YES if not transmitted
* #GNUNET_SYSERR when request was canceled
*/
int was_transmitted;
/**
* Did we add this request to the queue?
*/
int was_queued;
/**
* Desired direction (IP to name or name to IP)
*/
int direction;
/**
* #GNUNET_YES if a response was received
*/
int received_response;
/**
* Length of the data that follows this struct.
*/
size_t data_len;
};
/**
* Check that the resolver service runs on localhost
* (or equivalent).
*
* @return #GNUNET_OK if the resolver is properly configured,
* #GNUNET_SYSERR otherwise.
*/
static int
check_config ()
{
char *hostname;
struct sockaddr_in v4;
struct sockaddr_in6 v6;
memset (&v4, 0, sizeof (v4));
v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
v4.sin_family = AF_INET;
#if HAVE_SOCKADDR_IN_SIN_LEN
v4.sin_len = sizeof (v4);
#endif
memset (&v6, 0, sizeof (v6));
v6.sin6_family = AF_INET6;
#if HAVE_SOCKADDR_IN_SIN_LEN
v6.sin6_len = sizeof (v6);
#endif
if (GNUNET_OK !=