+/**
+ * Handle for miniupnp-based NAT traversal actions.
+ */
+struct MiniList
+{
+
+ /**
+ * Doubly-linked list.
+ */
+ struct MiniList *next;
+
+ /**
+ * Doubly-linked list.
+ */
+ struct MiniList *prev;
+
+ /**
+ * Handle to mini-action.
+ */
+ struct GNUNET_NAT_MiniHandle *mini;
+
+ /**
+ * Local port number that was mapped.
+ */
+ uint16_t port;
+
+};
+
+
+/**
+ * Handle for active NAT registrations.
+ */
+struct GNUNET_NAT_Handle
+{
+
+ /**
+ * Configuration to use.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Function to call when we learn about a new address.
+ */
+ GNUNET_NAT_AddressCallback address_callback;
+
+ /**
+ * Function to call when we notice another peer asking for
+ * connection reversal.
+ */
+ GNUNET_NAT_ReversalCallback reversal_callback;
+
+ /**
+ * Closure for 'callback'.
+ */
+ void *callback_cls;
+
+ /**
+ * Handle for (DYN)DNS lookup of our external IP.
+ */
+ struct GNUNET_RESOLVER_RequestHandle *ext_dns;
+
+ /**
+ * Handle for request of hostname resolution, non-NULL if pending.
+ */
+ struct GNUNET_RESOLVER_RequestHandle *hostname_dns;
+
+ /**
+ * stdout pipe handle for the gnunet-helper-nat-server process
+ */
+ struct GNUNET_DISK_PipeHandle *server_stdout;
+
+ /**
+ * stdout file handle (for reading) for the gnunet-helper-nat-server process
+ */
+ const struct GNUNET_DISK_FileHandle *server_stdout_handle;
+
+ /**
+ * Linked list of currently valid addresses (head).
+ */
+ struct LocalAddressList *lal_head;
+
+ /**
+ * Linked list of currently valid addresses (tail).
+ */
+ struct LocalAddressList *lal_tail;
+
+ /**
+ * How long do we wait for restarting a crashed gnunet-helper-nat-server?
+ */
+ struct GNUNET_TIME_Relative server_retry_delay;
+
+ /**
+ * ID of select gnunet-helper-nat-server stdout read task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier server_read_task;
+
+ /**
+ * ID of interface IP-scan task
+ */
+ 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;
+
+ /**
+ * ID of task to add addresses from bind.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier bind_task;
+
+ /**
+ * How often do we scan for changes in our IP address from our local
+ * interfaces?
+ */
+ struct GNUNET_TIME_Relative ifc_scan_frequency;
+
+ /**
+ * How often do we scan for changes in how our hostname resolves?
+ */
+ struct GNUNET_TIME_Relative hostname_dns_frequency;
+
+ /**
+ * How often do we scan for changes in how our external (dyndns) hostname resolves?
+ */
+ struct GNUNET_TIME_Relative dyndns_frequency;
+
+ /**
+ * The process id of the server process (if behind NAT)
+ */
+ struct GNUNET_OS_Process *server_proc;
+
+ /**
+ * LAN address as passed by the caller (array).
+ */
+ struct sockaddr **local_addrs;
+
+ /**
+ * Length of the 'local_addrs'.
+ */
+ socklen_t *local_addrlens;
+
+ /**
+ * List of handles for UPnP-traversal, one per local port (if
+ * not IPv6-only).
+ */
+ struct MiniList *mini_head;
+
+ /**
+ * List of handles for UPnP-traversal, one per local port (if
+ * not IPv6-only).
+ */
+ struct MiniList *mini_tail;
+
+ /**
+ * Number of entries in 'local_addrs' array.
+ */
+ unsigned int num_local_addrs;
+
+ /**
+ * Our external address (according to config, UPnP may disagree...),
+ * in dotted decimal notation, IPv4-only. Or NULL if not known.
+ */
+ char *external_address;
+
+ /**
+ * Presumably our internal address (according to config)
+ */
+ char *internal_address;
+
+ /**
+ * Is this transport configured to be behind a NAT?
+ */
+ int behind_nat;
+
+ /**
+ * Has the NAT been punched? (according to config)
+ */
+ int nat_punched;
+
+ /**
+ * Is this transport configured to allow connections to NAT'd peers?
+ */
+ int enable_nat_client;
+
+ /**
+ * Should we run the gnunet-helper-nat-server?
+ */
+ int enable_nat_server;
+
+ /**
+ * Are we allowed to try UPnP/PMP for NAT traversal?
+ */
+ int enable_upnp;
+
+ /**
+ * Should we use local addresses (loopback)? (according to config)
+ */
+ int use_localaddresses;
+
+ /**
+ * Should we return local addresses to clients
+ */
+ int return_localaddress;
+
+ /**
+ * Should we do a DNS lookup of our hostname to find out our own IP?
+ */
+ int use_hostname;
+
+ /**
+ * Is using IPv6 disabled?
+ */
+ int disable_ipv6;
+
+ /**
+ * Is this TCP or UDP?
+ */
+ int is_tcp;
+
+ /**
+ * Port we advertise to the outside.
+ */
+ uint16_t adv_port;
+
+};
+
+
+/**
+ * Try to start the gnunet-helper-nat-server (if it is not
+ * already running).
+ *
+ * @param h handle to NAT
+ */
+static void
+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 h handle to NAT
+ * @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);
+ if (NULL != h->address_callback)
+ h->address_callback (h->callback_cls, GNUNET_NO,
+ (const struct sockaddr *) &pos[1], pos->addrlen);
+ GNUNET_free (pos);
+ }