*
* TODO:
* Basics:
- * - need some logging
- * - need some statistics
* - test!
- * - better message queue management (bounded state, drop oldest/RED?)
- * - actually destroy "stale" tunnels once we have too many!
*
* Features:
* - add back ICMP support (especially needed for IPv6)
#include "gnunet_protocols.h"
#include "gnunet_applications.h"
#include "gnunet_mesh_service.h"
+#include "gnunet_statistics_service.h"
#include "gnunet_constants.h"
#include "tcpip_tun.h"
#include "vpn.h"
#include "exit.h"
+/**
+ * Maximum number of messages we allow in the queue for mesh.
+ */
+#define MAX_MESSAGE_QUEUE_SIZE 4
+
+
/**
* State we keep for each of our tunnels.
*/
/**
* Key under which this entry is in the 'destination_map' (only valid
- * if 'heap_node != NULL'.
+ * if 'heap_node != NULL').
*/
GNUNET_HashCode key;
*/
struct TunnelState
{
+
/**
* Information about the tunnel to use, NULL if no tunnel
* is available right now.
/**
* Head of list of messages scheduled for transmission.
*/
- struct TunnelMessageQueueEntry *head;
+ struct TunnelMessageQueueEntry *tmq_head;
/**
* Tail of list of messages scheduled for transmission.
*/
- struct TunnelMessageQueueEntry *tail;
+ struct TunnelMessageQueueEntry *tmq_tail;
/**
* Client that needs to be notified about the tunnel being
*/
struct GNUNET_SERVER_Client *client;
+ /**
+ * Destination entry that has a pointer to this tunnel state;
+ * NULL if this tunnel state is in the tunnel map.
+ */
+ struct DestinationEntry *destination_container;
+
/**
* ID of the client request that caused us to setup this entry.
*/
struct DestinationEntry destination;
/**
- * Destination entry that has a pointer to this tunnel state;
- * NULL if this tunnel state is in the tunnel map.
+ * Task scheduled to destroy the tunnel (or NO_TASK).
*/
- struct DestinationEntry *destination_container;
+ GNUNET_SCHEDULER_TaskIdentifier destroy_task;
/**
* Addess family used for this tunnel on the local TUN interface.
*/
int af;
+ /**
+ * Length of the doubly linked 'tmq_head/tmq_tail' list.
+ */
+ unsigned int tmq_length;
+
/**
* IPPROTO_TCP or IPPROTO_UDP once bound.
*/
*/
static struct GNUNET_CONTAINER_Heap *tunnel_heap;
+/**
+ * Statistics.
+ */
+static struct GNUNET_STATISTICS_Handle *stats;
+
/**
* The handle to the VPN helper process "gnunet-helper-vpn".
*/
}
+/**
+ * Destroy the mesh tunnel.
+ *
+ * @param cls the 'struct TunnelState' with the tunnel to destroy
+ * @param ts schedule context
+ */
+static void
+destroy_tunnel_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct TunnelState *ts = cls;
+ struct GNUNET_MESH_Tunnel *tunnel;
+
+ ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
+ if (NULL == (tunnel = ts->tunnel))
+ return;
+ ts->tunnel = NULL;
+ GNUNET_MESH_tunnel_destroy (tunnel);
+}
+
+
/**
* Method called whenever a peer has disconnected from the tunnel.
*
GNUNET_PeerIdentity * peer)
{
struct TunnelState *ts = cls;
-
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %s disconnected from tunnel.\n",
+ GNUNET_i2s (peer));
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Peers connected to mesh tunnels"),
+ -1, GNUNET_NO);
if (NULL != ts->th)
{
GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
return; /* hope for reconnect eventually */
/* as we are most likely going to change the exit node now,
we should just destroy the tunnel entirely... */
- GNUNET_MESH_tunnel_destroy (ts->tunnel);
+ if (GNUNET_SCHEDULER_NO_TASK == ts->destroy_task)
+ ts->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_tunnel_task, ts);
}
{
struct TunnelState *ts = cls;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %s connected to tunnel.\n",
+ GNUNET_i2s (peer));
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Peers connected to mesh tunnels"),
+ 1, GNUNET_NO);
if (NULL == ts->client)
return; /* nothing to do */
send_client_reply (ts->client,
ts->th = NULL;
if (NULL == buf)
return 0;
- tnq = ts->head;
+ tnq = ts->tmq_head;
GNUNET_assert (NULL != tnq);
GNUNET_assert (size >= tnq->len);
- GNUNET_CONTAINER_DLL_remove (ts->head,
- ts->tail,
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending %u bytes via mesh tunnel\n",
+ tnq->len);
+ GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
+ ts->tmq_tail,
tnq);
+ ts->tmq_length--;
memcpy (buf, tnq->msg, tnq->len);
ret = tnq->len;
GNUNET_free (tnq);
- if (NULL != (tnq = ts->head))
+ if (NULL != (tnq = ts->tmq_head))
ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
GNUNET_NO /* cork */,
42 /* priority */,
tnq->len,
&send_to_peer_notify_callback,
ts);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Bytes given to mesh for transmission"),
+ ret, GNUNET_NO);
return ret;
}
* Add the given message to the given tunnel and trigger the
* transmission process.
*
- * FIXME: bound queue length!
- *
* @param tnq message to queue
* @param ts tunnel to queue the message for
*/
send_to_tunnel (struct TunnelMessageQueueEntry *tnq,
struct TunnelState *ts)
{
- GNUNET_CONTAINER_DLL_insert_tail (ts->head,
- ts->tail,
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Queueing %u bytes for transmission via mesh tunnel\n",
+ tnq->len);
+ GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head,
+ ts->tmq_tail,
tnq);
+ ts->tmq_length++;
+ if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE)
+ {
+ struct TunnelMessageQueueEntry *dq;
+
+ dq = ts->tmq_head;
+ GNUNET_assert (dq != tnq);
+ GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
+ ts->tmq_tail,
+ dq);
+ GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
+ ts->th = NULL;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Bytes dropped in mesh queue (overflow)"),
+ dq->len,
+ GNUNET_NO);
+ GNUNET_free (dq);
+ }
if (NULL == ts->th)
ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
GNUNET_NO /* cork */,
{
struct TunnelState *ts;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Mesh tunnels created"),
+ 1, GNUNET_NO);
GNUNET_assert (NULL == de->ts);
ts = GNUNET_malloc (sizeof (struct TunnelState));
if (NULL != client)
ts);
if (de->is_service)
{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating tunnel to peer %s offering service %s\n",
+ GNUNET_i2s (&de->details.service_destination.target),
+ GNUNET_h2s (&de->details.service_destination.service_descriptor));
GNUNET_MESH_peer_request_connect_add (ts->tunnel,
&de->details.service_destination.target);
}
case AF_INET:
GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
GNUNET_APPLICATION_TYPE_IPV4_GATEWAY);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating tunnel to exit peer for %s\n",
+ "IPv4");
break;
case AF_INET6:
GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
GNUNET_APPLICATION_TYPE_IPV6_GATEWAY);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating tunnel to exit peer for %s\n",
+ "IPv6");
break;
default:
GNUNET_assert (0);
}
+/**
+ * Free resources associated with a tunnel state.
+ *
+ * @param ts state to free
+ */
+static void
+free_tunnel_state (struct TunnelState *ts)
+{
+ GNUNET_HashCode key;
+ struct TunnelMessageQueueEntry *tnq;
+ struct GNUNET_MESH_Tunnel *tunnel;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Cleaning up tunnel state\n");
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Active tunnels"),
+ -1, GNUNET_NO);
+ if (GNUNET_SCHEDULER_NO_TASK != ts->destroy_task)
+ {
+ GNUNET_SCHEDULER_cancel (ts->destroy_task);
+ ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ while (NULL != (tnq = ts->tmq_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
+ ts->tmq_tail,
+ tnq);
+ ts->tmq_length--;
+ GNUNET_free (tnq);
+ }
+ GNUNET_assert (0 == ts->tmq_length);
+ if (NULL != ts->client)
+ {
+ GNUNET_SERVER_client_drop (ts->client);
+ ts->client = NULL;
+ }
+ if (NULL != ts->th)
+ {
+ GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
+ ts->th = NULL;
+ }
+ GNUNET_assert (NULL == ts->destination.heap_node);
+ if (NULL != (tunnel = ts->tunnel))
+ {
+ ts->tunnel = NULL;
+ GNUNET_MESH_tunnel_destroy (tunnel);
+ }
+ if (NULL != ts->heap_node)
+ {
+ GNUNET_CONTAINER_heap_remove_node (ts->heap_node);
+ ts->heap_node = NULL;
+ get_tunnel_key_from_ips (ts->af,
+ ts->protocol,
+ &ts->source_ip,
+ ts->source_port,
+ &ts->destination_ip,
+ ts->destination_port,
+ &key);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (tunnel_map,
+ &key,
+ ts));
+ }
+ if (NULL != ts->destination_container)
+ {
+ GNUNET_assert (ts == ts->destination_container->ts);
+ ts->destination_container->ts = NULL;
+ ts->destination_container = NULL;
+ }
+ GNUNET_free (ts);
+}
+
+
+/**
+ * We have too many active tunnels. Clean up the oldest tunnel.
+ *
+ * @param except tunnel that must NOT be cleaned up, even if it is the oldest
+ */
+static void
+expire_tunnel (struct TunnelState *except)
+{
+ struct TunnelState *ts;
+
+ ts = GNUNET_CONTAINER_heap_peek (tunnel_heap);
+ if (except == ts)
+ return; /* can't do this */
+ free_tunnel_state (ts);
+}
+
+
/**
* Route a packet via mesh to the given destination.
*
struct TunnelMessageQueueEntry *tnq;
size_t alen;
size_t mlen;
- GNUNET_MESH_ApplicationType app_type;
int is_new;
const struct udp_packet *udp;
const struct tcp_packet *tcp;
(unsigned int) protocol);
return;
}
-
if (! destination->is_service)
{
switch (destination->details.exit_destination.af)
{
case AF_INET:
alen = sizeof (struct in_addr);
- app_type = GNUNET_APPLICATION_TYPE_IPV4_GATEWAY;
break;
case AF_INET6:
alen = sizeof (struct in6_addr);
- app_type = GNUNET_APPLICATION_TYPE_IPV6_GATEWAY;
break;
default:
alen = 0;
GNUNET_assert (0);
}
+
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
+ char xbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
+ (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
+ inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
+ spt,
+ inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
+ dpt,
+ inet_ntop (destination->details.exit_destination.af,
+ &destination->details.exit_destination.ip,
+ xbuf, sizeof (xbuf)));
+ }
}
else
{
/* make compiler happy */
alen = 0;
- app_type = 0;
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
+ (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
+ inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
+ spt,
+ inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
+ dpt,
+ GNUNET_h2s (&destination->details.service_destination.service_descriptor),
+ GNUNET_i2s (&destination->details.service_destination.target));
+ }
+
}
/* see if we have an existing tunnel for this destination */
&key,
ts,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- /* FIXME: expire OLD tunnels if we have too many! */
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Active tunnels"),
+ 1, GNUNET_NO);
+ while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
+ expire_tunnel (ts);
}
else
{
return;
}
tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
+ tnq->len = mlen;
+ tnq->msg = &tnq[1];
usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
usm->header.size = htons ((uint16_t) mlen);
usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
}
tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
mlen);
+ tnq->len = mlen;
+ tnq->msg = &tnq[1];
uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
uim->header.size = htons ((uint16_t) mlen);
uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
return;
}
tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
+ tnq->len = mlen;
+ tnq->msg = &tnq[1];
tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
tsm->header.size = htons ((uint16_t) mlen);
tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
return;
}
tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
+ tnq->len = mlen;
+ tnq->msg = &tnq[1];
tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
tim->header.size = htons ((uint16_t) mlen);
tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
return;
}
tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
+ tnq->len = mlen;
+ tnq->msg = &tnq[1];
tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
tdm->header.size = htons ((uint16_t) mlen);
tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA);
GNUNET_HashCode key;
struct DestinationEntry *de;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Packets received from TUN interface"),
+ 1, GNUNET_NO);
mlen = ntohs (message->size);
if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
(mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header)) )
const struct GNUNET_EXIT_UdpReplyMessage *reply;
size_t mlen;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# UDP packets received from mesh"),
+ 1, GNUNET_NO);
mlen = ntohs (message->size);
if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
{
}
reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
+ (unsigned int) mlen,
+ inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
+ ts->destination_port,
+ inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
+ ts->source_port);
+ }
switch (ts->af)
{
case AF_INET:
const struct GNUNET_EXIT_TcpDataMessage *data;
size_t mlen;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# TCP packets received from mesh"),
+ 1, GNUNET_NO);
mlen = ntohs (message->size);
if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
{
}
data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
+ (unsigned int) mlen,
+ inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
+ ts->destination_port,
+ inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
+ ts->source_port);
+ }
switch (ts->af)
{
case AF_INET:
}
+/**
+ * Free resources occupied by a destination entry.
+ *
+ * @param de entry to free
+ */
+static void
+free_destination_entry (struct DestinationEntry *de)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Cleaning up destination entry\n");
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Active destinations"),
+ -1, GNUNET_NO);
+ if (NULL != de->ts)
+ {
+ free_tunnel_state (de->ts);
+ GNUNET_assert (NULL == de->ts);
+ }
+ if (NULL != de->heap_node)
+ {
+ GNUNET_CONTAINER_heap_remove_node (de->heap_node);
+ de->heap_node = NULL;
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (destination_map,
+ &de->key,
+ de));
+ }
+ GNUNET_free (de);
+}
+
+
+/**
+ * We have too many active destinations. Clean up the oldest destination.
+ *
+ * @param except destination that must NOT be cleaned up, even if it is the oldest
+ */
+static void
+expire_destination (struct DestinationEntry *except)
+{
+ struct DestinationEntry *de;
+
+ de = GNUNET_CONTAINER_heap_peek (destination_heap);
+ if (except == de)
+ return; /* can't do this */
+ free_destination_entry (de);
+}
+
+
/**
* A client asks us to setup a redirection via some exit
* node to a particular IP. Setup the redirection and
void *addr;
struct DestinationEntry *de;
GNUNET_HashCode key;
- GNUNET_MESH_ApplicationType app_type;
/* validate and parse request */
mlen = ntohs (message->size);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
- app_type = GNUNET_APPLICATION_TYPE_IPV4_GATEWAY;
break;
case AF_INET6:
if (alen != sizeof (struct in6_addr))
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
- app_type = GNUNET_APPLICATION_TYPE_IPV6_GATEWAY;
break;
default:
GNUNET_break (0);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
+
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Allocated address %s for redirection via exit to %s\n",
+ inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
+ inet_ntop (addr_af,
+ &msg[1], dbuf, sizeof (dbuf)));
+ }
/* setup destination record */
de = GNUNET_malloc (sizeof (struct DestinationEntry));
de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
de,
GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
- /* FIXME: expire OLD destinations if we have too many! */
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Active destinations"),
+ 1, GNUNET_NO);
+ while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
+ expire_destination (de);
+
/* setup tunnel to destination */
(void) create_tunnel_to_destination (de,
(GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
if (result_af == AF_UNSPEC)
{
/* failure, we're done */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to allocate IP address for new destination\n"));
GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
+
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Allocated address %s for redirection to service %s on peer %s\n",
+ inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
+ GNUNET_h2s (&msg->service_descriptor),
+ GNUNET_i2s (&msg->target));
+ }
/* setup destination record */
de = GNUNET_malloc (sizeof (struct DestinationEntry));
de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
de,
GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
- /* FIXME: expire OLD destinations if we have too many! */
+ while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
+ expire_destination (de);
(void) create_tunnel_to_destination (de,
(GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
msg->request_id);
}
-/**
- * Free resources associated with a tunnel state.
- *
- * @param ts state to free
- */
-static void
-free_tunnel_state (struct TunnelState *ts)
-{
- GNUNET_HashCode key;
- struct TunnelMessageQueueEntry *tnq;
-
- while (NULL != (tnq = ts->head))
- {
- GNUNET_CONTAINER_DLL_remove (ts->head,
- ts->tail,
- tnq);
- GNUNET_free (tnq);
- }
- if (NULL != ts->client)
- {
- GNUNET_SERVER_client_drop (ts->client);
- ts->client = NULL;
- }
- if (NULL != ts->th)
- {
- GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
- ts->th = NULL;
- }
- GNUNET_assert (NULL == ts->destination.heap_node);
- if (NULL != ts->tunnel)
- {
- GNUNET_MESH_tunnel_destroy (ts->tunnel);
- ts->tunnel = NULL;
- }
- if (NULL != ts->heap_node)
- {
- GNUNET_CONTAINER_heap_remove_node (ts->heap_node);
- ts->heap_node = NULL;
- get_tunnel_key_from_ips (ts->af,
- ts->protocol,
- &ts->source_ip,
- ts->source_port,
- &ts->destination_ip,
- ts->destination_port,
- &key);
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_remove (tunnel_map,
- &key,
- ts));
- }
- if (NULL != ts->destination_container)
- {
- GNUNET_assert (ts == ts->destination_container->ts);
- ts->destination_container->ts = NULL;
- ts->destination_container = NULL;
- }
- GNUNET_free (ts);
-}
-
-
-/**
- * Free resources occupied by a destination entry.
- *
- * @param de entry to free
- */
-static void
-free_destination_entry (struct DestinationEntry *de)
-{
- if (NULL != de->ts)
- {
- free_tunnel_state (de->ts);
- GNUNET_assert (NULL == de->ts);
- }
- if (NULL != de->heap_node)
- {
- GNUNET_CONTAINER_heap_remove_node (de->heap_node);
- de->heap_node = NULL;
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_remove (destination_map,
- &de->key,
- de));
- }
- GNUNET_free (de);
-}
-
-
/**
* Function called whenever an inbound tunnel is destroyed. Should clean up
* any associated state.
{
unsigned int i;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "VPN is shutting down\n");
if (NULL != destination_map)
{
GNUNET_CONTAINER_multihashmap_iterate (destination_map,
GNUNET_SERVER_notification_context_destroy (nc);
nc = NULL;
}
+ if (stats != NULL)
+ {
+ GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
+ stats = NULL;
+ }
for (i=0;i<5;i++)
GNUNET_free_non_null (vpn_argv[i]);
}
struct in6_addr v6;
cfg = cfg_;
+ stats = GNUNET_STATISTICS_create ("vpn", cfg);
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
&max_destination_mappings))