*
* TODO:
* - implement UPnP/PMP support
- * - repeatedly perform certain checks again to notice changes
+ * - make frequency of checks configurable
*/
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_resolver_service.h"
#include "gnunet_nat_lib.h"
+/**
+ * How often do we scan for changes in our IP address from our local
+ * interfaces?
+ * FIXME: make this configurable...
+ */
+#define IFC_SCAN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
+
+/**
+ * How often do we scan for changes in how our hostname resolves?
+ * FIXME: make this configurable...
+ */
+#define HOSTNAME_DNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 20)
+
+
+/**
+ * How often do we scan for changes in how our external (dyndns) hostname resolves?
+ * FIXME: make this configurable...
+ */
+#define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 7)
/**
* How long until we give up on transmitting the welcome message?
/**
* Address was obtained by DNS resolution of the external hostname
* given in the configuration (i.e. hole-punched DynDNS setup).
- * FIXME: repeatedly do the lookup to notice changes!
*/
LAL_EXTERNAL_IP,
/**
* Address was obtained by looking up our own hostname in DNS.
- * FIXME: repeatedly do the lookup to notice changes!
*/
LAL_HOSTNAME_DNS,
/**
* Address was obtained by scanning our hosts's network interfaces
* and taking their address (no DNS involved).
- * FIXME: repeatedly do the lookup to notice changes!
*/
LAL_INTERFACE_ADDRESS,
*/
GNUNET_SCHEDULER_TaskIdentifier ifc_task;
+ /**
+ * ID of hostname DNS lookup task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier hostname_task;
+
+ /**
+ * ID of DynDNS lookup task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier dns_task;
+
/**
* The process id of the server process (if behind NAT)
*/
start_gnunet_nat_server (struct GNUNET_NAT_Handle *h);
+/**
+ * Remove all addresses from the list of 'local' addresses
+ * that originated from the given source.
+ *
+ * @param plugin the plugin
+ * @param src source that identifies addresses to remove
+ */
+static void
+remove_from_address_list_by_source (struct GNUNET_NAT_Handle *h,
+ enum LocalAddressSource src)
+{
+ struct LocalAddressList *pos;
+ struct LocalAddressList *next;
+
+ next = h->lal_head;
+ while (NULL != (pos = next))
+ {
+ next = pos->next;
+ if (pos->source != src)
+ continue;
+ GNUNET_CONTAINER_DLL_remove (h->lal_head,
+ h->lal_tail,
+ pos);
+ h->address_callback (h->callback_cls,
+ GNUNET_NO,
+ (const struct sockaddr* ) &pos[1],
+ pos->addrlen);
+ GNUNET_free (pos);
+ }
+}
+
+
/**
* Add the given address to the list of 'local' addresses, thereby
* making it a 'legal' address for this peer to have.
}
+/**
+ * Task to do DNS lookup on our external hostname to
+ * get DynDNS-IP addresses.
+ *
+ * @param cls the NAT handle
+ * @param tc scheduler context
+ */
+static void
+resolve_dns (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
/**
* Our (external) hostname was resolved and the configuration says that
* the NAT was hole-punched.
if (addr == NULL)
{
h->ext_dns = NULL;
- /* FIXME: schedule task to resolve IP again in the
- future, and if the result changes, update the
- local address list accordingly */
+ h->dns_task = GNUNET_SCHEDULER_add_delayed (DYNDNS_FREQUENCY,
+ &resolve_dns, h);
return;
}
add_to_address_list (h, LAL_EXTERNAL_IP, addr, addrlen);
}
+/**
+ * Task to do a lookup on our hostname for IP addresses.
+ *
+ * @param cls the NAT handle
+ * @param tc scheduler context
+ */
+static void
+resolve_hostname (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
/**
* Function called by the resolver for each address obtained from DNS
* for our own hostname. Add the addresses to the list of our IP
if (addr == NULL)
{
h->hostname_dns = NULL;
- /* FIXME: schedule task to resolve IP again in the
- future, and if the result changes, update the
- address list accordingly */
+ h->hostname_task = GNUNET_SCHEDULER_add_delayed (HOSTNAME_DNS_FREQUENCY,
+ &resolve_hostname, h);
return;
}
add_to_address_list (h, LAL_HOSTNAME_DNS, addr, addrlen);
struct GNUNET_NAT_Handle *h = cls;
h->ifc_task = GNUNET_SCHEDULER_NO_TASK;
+ remove_from_address_list_by_source (h, LAL_INTERFACE_ADDRESS);
GNUNET_OS_network_interfaces_list (&process_interfaces, h);
-#if 0
- h->ifc_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FIXME,
+ h->ifc_task = GNUNET_SCHEDULER_add_delayed (IFC_SCAN_FREQUENCY,
&list_interfaces, h);
-#endif
+}
+
+
+/**
+ * Task to do a lookup on our hostname for IP addresses.
+ *
+ * @param cls the NAT handle
+ * @param tc scheduler context
+ */
+static void
+resolve_hostname (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_NAT_Handle *h = cls;
+
+ h->hostname_task = GNUNET_SCHEDULER_NO_TASK;
+ remove_from_address_list_by_source (h, LAL_HOSTNAME_DNS);
+ h->hostname_dns = GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC,
+ HOSTNAME_RESOLVE_TIMEOUT,
+ &process_hostname_ip,
+ h);
+}
+
+
+/**
+ * Task to do DNS lookup on our external hostname to
+ * get DynDNS-IP addresses.
+ *
+ * @param cls the NAT handle
+ * @param tc scheduler context
+ */
+static void
+resolve_dns (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_NAT_Handle *h = cls;
+
+ h->dns_task = GNUNET_SCHEDULER_NO_TASK;
+ remove_from_address_list_by_source (h, LAL_EXTERNAL_IP);
+ h->ext_dns = GNUNET_RESOLVER_ip_get (h->external_address,
+ AF_INET,
+ GNUNET_TIME_UNIT_MINUTES,
+ &process_external_ip,
+ h);
}
(h->external_address != NULL) &&
(h->nat_punched == GNUNET_YES) )
{
- h->ext_dns = GNUNET_RESOLVER_ip_get (h->external_address,
- AF_INET,
- GNUNET_TIME_UNIT_MINUTES,
- &process_external_ip,
- h);
+ h->dns_task = GNUNET_SCHEDULER_add_now (&resolve_dns, h);
h->enable_nat_server = GNUNET_NO;
h->enable_upnp = GNUNET_NO;
}
if (NULL != h->address_callback)
{
h->ifc_task = GNUNET_SCHEDULER_add_now (&list_interfaces, h);
- h->hostname_dns = GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC,
- HOSTNAME_RESOLVE_TIMEOUT,
- &process_hostname_ip,
- h);
+ h->hostname_task = GNUNET_SCHEDULER_add_now (&resolve_hostname, h);
}
return h;
}
GNUNET_SCHEDULER_cancel (h->ifc_task);
h->ifc_task = GNUNET_SCHEDULER_NO_TASK;
}
+ if (GNUNET_SCHEDULER_NO_TASK != h->hostname_task)
+ {
+ GNUNET_SCHEDULER_cancel (h->hostname_task);
+ h->hostname_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != h->dns_task)
+ {
+ GNUNET_SCHEDULER_cancel (h->dns_task);
+ h->dns_task = GNUNET_SCHEDULER_NO_TASK;
+ }
if (NULL != h->server_proc)
{
if (0 != GNUNET_OS_process_kill (h->server_proc, SIGTERM))
*/
static struct GNUNET_STATISTICS_Handle *stats;
+/**
+ * Identifier of 'refresh_hello' task.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier hello_task;
+
/**
* Is transport service shutting down ?
*/
/**
* Construct our HELLO message from all of the addresses of
* all of the transports.
+ *
+ * @param cls unused
+ * @param tc scheduler context
*/
static void
-refresh_hello ()
+refresh_hello_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
{
struct GNUNET_HELLO_Message *hello;
struct TransportClient *cpos;
struct NeighbourList *npos;
struct GeneratorContext gc;
+ hello_task = GNUNET_SCHEDULER_NO_TASK;
gc.plug_pos = plugins;
gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
}
+/**
+ * Schedule task to refresh hello (unless such a
+ * task exists already).
+ */
+static void
+refresh_hello ()
+{
+ if (hello_task != GNUNET_SCHEDULER_NO_TASK)
+ return;
+ hello_task
+ = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
+ NULL);
+}
+
+
/**
* Iterator over hash map entries that NULLs the session of validation
* entries that match the given session.
return;
}
if (NULL == our_hello)
- refresh_hello ();
+ refresh_hello_task (NULL, NULL);
hello_size = GNUNET_HELLO_size(our_hello);
slen = strlen(va->transport_name) + 1;
tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
GNUNET_PEERINFO_disconnect (peerinfo);
peerinfo = NULL;
}
+ if (GNUNET_SCHEDULER_NO_TASK != hello_task)
+ {
+ GNUNET_SCHEDULER_cancel (hello_task);
+ hello_task = GNUNET_SCHEDULER_NO_TASK;
+ }
/* Can we assume those are gone by now, or do we need to clean up
explicitly!? */
GNUNET_break (bl_head == NULL);
ats_init();
#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Transport service ready.\n"));
#endif
/* If we have a blacklist file, read from it */
read_blacklist_file(cfg);