+ h->ifc_task = NULL;
+ remove_from_address_list_by_source (h, LAL_INTERFACE_ADDRESS);
+ GNUNET_OS_network_interfaces_list (&process_interfaces, h);
+ h->ifc_task =
+ GNUNET_SCHEDULER_add_delayed (h->ifc_scan_frequency,
+ &list_interfaces, h);
+}
+
+
+
+/**
+ * Callback if the STun request have a error
+ *
+ * @param cls the NAT handle
+ * @param result , the status
+ */
+static void
+stun_request_callback(void *cls,
+ enum GNUNET_NAT_StatusCode result)
+{
+
+ struct GNUNET_NAT_Handle *h = cls;
+
+ if(NULL == cls)
+ return;
+
+ h->waiting_stun = GNUNET_NO;
+
+ if(result != GNUNET_OK)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Error processing a STUN request");
+ }
+
+};
+
+/**
+ * CHECK if is a valid STUN packet sending to GNUNET_NAT_stun_handle_packet.
+ * It also check if it can handle the packet based on the NAT handler.
+ * You don't need to call anything else to check if the packet is valid,
+ *
+ * @param cls the NAT handle
+ * @param data, packet
+ * @param len, packet length
+ *
+ * @return #GNUNET_NO if it can't decode, #GNUNET_YES if is a packet
+ */
+int
+GNUNET_NAT_is_valid_stun_packet(void *cls, const void *data, size_t len)
+{
+ struct GNUNET_NAT_Handle *h = cls;
+ struct sockaddr_in answer;
+
+ /* We are not expecting a STUN message*/
+ if(!h->waiting_stun)
+ return GNUNET_NO;
+
+ /*We dont have STUN installed*/
+ if(!h->use_stun)
+ return GNUNET_NO;
+
+ /* Empty the answer structure */
+ memset(&answer, 0, sizeof(struct sockaddr_in));
+
+ /*Lets handle the packet*/
+ int valid = GNUNET_NAT_stun_handle_packet(data,len, &answer);
+ if(valid)
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Stun server returned IP %s , with port %d \n", inet_ntoa(answer.sin_addr), ntohs(answer.sin_port));
+ /* ADD IP AS VALID*/
+ add_to_address_list (h, LAL_EXTERNAL_IP, (const struct sockaddr *) &answer,
+ sizeof (struct sockaddr_in));
+ h->waiting_stun = GNUNET_NO;
+ return GNUNET_YES;
+ }
+ else
+ {
+ return GNUNET_NO;
+ }
+
+
+
+}
+
+/**
+ * Task to do a STUN request
+ *
+ * @param cls the NAT handle
+ * @param tc scheduler context
+ */
+static void
+process_stun (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_NAT_Handle *h = cls;
+
+ h->stun_task = NULL;
+
+
+
+ struct StunServerList* elem = h->actual_stun_server;
+
+ /* Make the request */
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "I will request the stun server %s:%i !\n", elem->address, elem->port);
+
+ if(GNUNET_OK == GNUNET_NAT_stun_make_request(elem->address, elem->port, h->socket, &stun_request_callback, NULL))
+ {
+ h->waiting_stun = GNUNET_YES;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "STUN request failed %s:%i !\n", elem->address, elem->port);
+ }
+
+ h->stun_task =
+ GNUNET_SCHEDULER_add_delayed (h->stun_frequency,
+ &process_stun, h);
+
+ /* Set actual Server*/
+ if(elem->next)
+ {
+ h->actual_stun_server = elem->next;
+ }
+ else
+ {
+ h->actual_stun_server = h->stun_servers_head;
+ }
+
+}
+
+
+
+/**
+ * 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 = NULL;
+ 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;
+ struct LocalAddressList *pos;
+
+ h->dns_task = NULL;
+ for (pos = h->lal_head; NULL != pos; pos = pos->next)
+ if (pos->source == LAL_EXTERNAL_IP)
+ pos->source = LAL_EXTERNAL_IP_OLD;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Resolving external address `%s'\n",
+ h->external_address);
+ h->ext_dns =
+ GNUNET_RESOLVER_ip_get (h->external_address, AF_INET,
+ GNUNET_TIME_UNIT_MINUTES,
+ &process_external_ip, h);
+}
+
+
+/**
+ * Add or remove UPnP-mapped addresses.
+ *
+ * @param cls the `struct GNUNET_NAT_Handle`
+ * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
+ * the previous (now invalid) one
+ * @param addr either the previous or the new public IP address
+ * @param addrlen actual lenght of @a addr
+ * @param ret GNUNET_NAT_ERROR_SUCCESS on success, otherwise an error code
+ */
+static void
+upnp_add (void *cls,
+ int add_remove,
+ const struct sockaddr *addr,
+ socklen_t addrlen,
+ enum GNUNET_NAT_StatusCode ret)
+{
+ struct GNUNET_NAT_Handle *h = cls;
+ struct LocalAddressList *pos;
+ struct LocalAddressList *next;
+
+
+ if (GNUNET_NAT_ERROR_SUCCESS != ret)
+ {
+ /* Error while running upnp client */
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Error while running upnp client:\n"));
+
+ //FIXME: convert error code to string
+
+ return;
+ }
+
+ if (GNUNET_YES == add_remove)
+ {
+ add_to_address_list (h, LAL_UPNP, addr, addrlen);
+ return;
+ }
+ else if (GNUNET_NO == add_remove)
+ {
+ /* remove address */
+ next = h->lal_head;
+ while (NULL != (pos = next))
+ {
+ next = pos->next;
+ if ((pos->source != LAL_UPNP) || (pos->addrlen != addrlen) ||
+ (0 != memcmp (&pos[1], addr, addrlen)))
+ 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);
+ return; /* only remove once */
+ }
+ /* asked to remove address that does not exist */
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Asked to remove unkown address `%s'\n",
+ GNUNET_a2s(addr, addrlen));
+ GNUNET_break (0);
+ }
+ else
+ {
+
+ GNUNET_break (0);
+ }
+}
+
+
+/**
+ * Try to add a port mapping using UPnP.
+ *
+ * @param h overall NAT handle
+ * @param port port to map with UPnP
+ */
+static void
+add_minis (struct GNUNET_NAT_Handle *h,
+ uint16_t port)
+{
+ struct MiniList *ml;
+
+ ml = h->mini_head;
+ while (NULL != ml)
+ {
+ if (port == ml->port)
+ return; /* already got this port */
+ ml = ml->next;
+ }
+
+ ml = GNUNET_new (struct MiniList);
+ ml->port = port;
+ ml->mini = GNUNET_NAT_mini_map_start (port, h->is_tcp, &upnp_add, h);
+
+ if (NULL == ml->mini)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to run upnp client for port %u\n"), ml->port);
+ GNUNET_free (ml);
+ return;
+ }
+
+ GNUNET_CONTAINER_DLL_insert (h->mini_head, h->mini_tail, ml);
+}
+
+
+/**
+ * Task to add addresses from original bind to set of valid addrs.
+ *
+ * @param h the NAT handle
+ */
+static void
+add_from_bind (struct GNUNET_NAT_Handle *h)
+{
+ static struct in6_addr any = IN6ADDR_ANY_INIT;
+
+ unsigned int i;
+ struct sockaddr *sa;
+ const struct sockaddr_in *v4;
+
+ for (i = 0; i < h->num_local_addrs; i++)
+ {
+ sa = h->local_addrs[i];
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ if (sizeof (struct sockaddr_in) != h->local_addrlens[i])
+ {
+ GNUNET_break (0);
+ break;
+ }
+ v4 = (const struct sockaddr_in *) sa;
+ if (0 != v4->sin_addr.s_addr)
+ add_to_address_list (h,
+ LAL_BINDTO_ADDRESS, sa,
+ sizeof (struct sockaddr_in));
+ if (h->enable_upnp)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Running upnp client for address `%s'\n",
+ GNUNET_a2s (sa,sizeof (struct sockaddr_in)));
+ add_minis (h, ntohs (v4->sin_port));
+ }
+ break;
+ case AF_INET6:
+ if (sizeof (struct sockaddr_in6) != h->local_addrlens[i])
+ {
+ GNUNET_break (0);
+ break;
+ }
+ if (0 !=
+ memcmp (&((const struct sockaddr_in6 *) sa)->sin6_addr,
+ &any,
+ sizeof (struct in6_addr)))
+ add_to_address_list (h,
+ LAL_BINDTO_ADDRESS,
+ sa,
+ sizeof (struct sockaddr_in6));
+ break;
+ default:
+ break;
+ }
+ }