diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-01-17 14:59:44 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-01-17 14:59:44 +0000 |
commit | 0bdf3ec3d40452b66e39b28e7e3694de8ead219e (patch) | |
tree | 93a2609bcc9569286235eca670bd5e2bc6c040a3 | |
parent | 851903da372fa136ff783bc92c3abe57f554786e (diff) | |
download | gnunet-0bdf3ec3d40452b66e39b28e7e3694de8ead219e.tar.gz gnunet-0bdf3ec3d40452b66e39b28e7e3694de8ead219e.zip |
-bound #messages queued, bound #destinations and bound #tunnels
-rw-r--r-- | src/vpn/gnunet-service-vpn.c | 269 |
1 files changed, 163 insertions, 106 deletions
diff --git a/src/vpn/gnunet-service-vpn.c b/src/vpn/gnunet-service-vpn.c index bb6e6c595..5d91d79f5 100644 --- a/src/vpn/gnunet-service-vpn.c +++ b/src/vpn/gnunet-service-vpn.c | |||
@@ -29,8 +29,6 @@ | |||
29 | * TODO: | 29 | * TODO: |
30 | * Basics: | 30 | * Basics: |
31 | * - test! | 31 | * - test! |
32 | * - better message queue management (bounded state, drop oldest/RED?) | ||
33 | * - actually destroy "stale" tunnels once we have too many! | ||
34 | * | 32 | * |
35 | * Features: | 33 | * Features: |
36 | * - add back ICMP support (especially needed for IPv6) | 34 | * - add back ICMP support (especially needed for IPv6) |
@@ -53,6 +51,12 @@ | |||
53 | 51 | ||
54 | 52 | ||
55 | /** | 53 | /** |
54 | * Maximum number of messages we allow in the queue for mesh. | ||
55 | */ | ||
56 | #define MAX_MESSAGE_QUEUE_SIZE 4 | ||
57 | |||
58 | |||
59 | /** | ||
56 | * State we keep for each of our tunnels. | 60 | * State we keep for each of our tunnels. |
57 | */ | 61 | */ |
58 | struct TunnelState; | 62 | struct TunnelState; |
@@ -67,7 +71,7 @@ struct DestinationEntry | |||
67 | 71 | ||
68 | /** | 72 | /** |
69 | * Key under which this entry is in the 'destination_map' (only valid | 73 | * Key under which this entry is in the 'destination_map' (only valid |
70 | * if 'heap_node != NULL'. | 74 | * if 'heap_node != NULL'). |
71 | */ | 75 | */ |
72 | GNUNET_HashCode key; | 76 | GNUNET_HashCode key; |
73 | 77 | ||
@@ -170,6 +174,7 @@ struct TunnelMessageQueueEntry | |||
170 | */ | 174 | */ |
171 | struct TunnelState | 175 | struct TunnelState |
172 | { | 176 | { |
177 | |||
173 | /** | 178 | /** |
174 | * Information about the tunnel to use, NULL if no tunnel | 179 | * Information about the tunnel to use, NULL if no tunnel |
175 | * is available right now. | 180 | * is available right now. |
@@ -606,8 +611,6 @@ send_to_peer_notify_callback (void *cls, size_t size, void *buf) | |||
606 | * Add the given message to the given tunnel and trigger the | 611 | * Add the given message to the given tunnel and trigger the |
607 | * transmission process. | 612 | * transmission process. |
608 | * | 613 | * |
609 | * FIXME: bound queue length! | ||
610 | * | ||
611 | * @param tnq message to queue | 614 | * @param tnq message to queue |
612 | * @param ts tunnel to queue the message for | 615 | * @param ts tunnel to queue the message for |
613 | */ | 616 | */ |
@@ -622,6 +625,23 @@ send_to_tunnel (struct TunnelMessageQueueEntry *tnq, | |||
622 | ts->tmq_tail, | 625 | ts->tmq_tail, |
623 | tnq); | 626 | tnq); |
624 | ts->tmq_length++; | 627 | ts->tmq_length++; |
628 | if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE) | ||
629 | { | ||
630 | struct TunnelMessageQueueEntry *dq; | ||
631 | |||
632 | dq = ts->tmq_head; | ||
633 | GNUNET_assert (dq != tnq); | ||
634 | GNUNET_CONTAINER_DLL_remove (ts->tmq_head, | ||
635 | ts->tmq_tail, | ||
636 | dq); | ||
637 | GNUNET_MESH_notify_transmit_ready_cancel (ts->th); | ||
638 | ts->th = NULL; | ||
639 | GNUNET_STATISTICS_update (stats, | ||
640 | gettext_noop ("# Bytes dropped in mesh queue (overflow)"), | ||
641 | dq->len, | ||
642 | GNUNET_NO); | ||
643 | GNUNET_free (dq); | ||
644 | } | ||
625 | if (NULL == ts->th) | 645 | if (NULL == ts->th) |
626 | ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel, | 646 | ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel, |
627 | GNUNET_NO /* cork */, | 647 | GNUNET_NO /* cork */, |
@@ -707,6 +727,90 @@ create_tunnel_to_destination (struct DestinationEntry *de, | |||
707 | 727 | ||
708 | 728 | ||
709 | /** | 729 | /** |
730 | * Free resources associated with a tunnel state. | ||
731 | * | ||
732 | * @param ts state to free | ||
733 | */ | ||
734 | static void | ||
735 | free_tunnel_state (struct TunnelState *ts) | ||
736 | { | ||
737 | GNUNET_HashCode key; | ||
738 | struct TunnelMessageQueueEntry *tnq; | ||
739 | |||
740 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
741 | "Cleaning up tunnel state\n"); | ||
742 | GNUNET_STATISTICS_update (stats, | ||
743 | gettext_noop ("# Active tunnels"), | ||
744 | -1, GNUNET_NO); | ||
745 | while (NULL != (tnq = ts->tmq_head)) | ||
746 | { | ||
747 | GNUNET_CONTAINER_DLL_remove (ts->tmq_head, | ||
748 | ts->tmq_tail, | ||
749 | tnq); | ||
750 | ts->tmq_length--; | ||
751 | GNUNET_free (tnq); | ||
752 | } | ||
753 | GNUNET_assert (0 == ts->tmq_length); | ||
754 | if (NULL != ts->client) | ||
755 | { | ||
756 | GNUNET_SERVER_client_drop (ts->client); | ||
757 | ts->client = NULL; | ||
758 | } | ||
759 | if (NULL != ts->th) | ||
760 | { | ||
761 | GNUNET_MESH_notify_transmit_ready_cancel (ts->th); | ||
762 | ts->th = NULL; | ||
763 | } | ||
764 | GNUNET_assert (NULL == ts->destination.heap_node); | ||
765 | if (NULL != ts->tunnel) | ||
766 | { | ||
767 | GNUNET_MESH_tunnel_destroy (ts->tunnel); | ||
768 | ts->tunnel = NULL; | ||
769 | } | ||
770 | if (NULL != ts->heap_node) | ||
771 | { | ||
772 | GNUNET_CONTAINER_heap_remove_node (ts->heap_node); | ||
773 | ts->heap_node = NULL; | ||
774 | get_tunnel_key_from_ips (ts->af, | ||
775 | ts->protocol, | ||
776 | &ts->source_ip, | ||
777 | ts->source_port, | ||
778 | &ts->destination_ip, | ||
779 | ts->destination_port, | ||
780 | &key); | ||
781 | GNUNET_assert (GNUNET_YES == | ||
782 | GNUNET_CONTAINER_multihashmap_remove (tunnel_map, | ||
783 | &key, | ||
784 | ts)); | ||
785 | } | ||
786 | if (NULL != ts->destination_container) | ||
787 | { | ||
788 | GNUNET_assert (ts == ts->destination_container->ts); | ||
789 | ts->destination_container->ts = NULL; | ||
790 | ts->destination_container = NULL; | ||
791 | } | ||
792 | GNUNET_free (ts); | ||
793 | } | ||
794 | |||
795 | |||
796 | /** | ||
797 | * We have too many active tunnels. Clean up the oldest tunnel. | ||
798 | * | ||
799 | * @param except tunnel that must NOT be cleaned up, even if it is the oldest | ||
800 | */ | ||
801 | static void | ||
802 | expire_tunnel (struct TunnelState *except) | ||
803 | { | ||
804 | struct TunnelState *ts; | ||
805 | |||
806 | ts = GNUNET_CONTAINER_heap_peek (tunnel_heap); | ||
807 | if (except == ts) | ||
808 | return; /* can't do this */ | ||
809 | free_tunnel_state (ts); | ||
810 | } | ||
811 | |||
812 | |||
813 | /** | ||
710 | * Route a packet via mesh to the given destination. | 814 | * Route a packet via mesh to the given destination. |
711 | * | 815 | * |
712 | * @param destination description of the destination | 816 | * @param destination description of the destination |
@@ -878,7 +982,8 @@ route_packet (struct DestinationEntry *destination, | |||
878 | GNUNET_STATISTICS_update (stats, | 982 | GNUNET_STATISTICS_update (stats, |
879 | gettext_noop ("# Active tunnels"), | 983 | gettext_noop ("# Active tunnels"), |
880 | 1, GNUNET_NO); | 984 | 1, GNUNET_NO); |
881 | /* FIXME: expire OLD tunnels if we have too many! */ | 985 | while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings) |
986 | expire_tunnel (ts); | ||
882 | } | 987 | } |
883 | else | 988 | else |
884 | { | 989 | { |
@@ -1662,6 +1767,54 @@ allocate_v6_address (struct in6_addr *v6) | |||
1662 | 1767 | ||
1663 | 1768 | ||
1664 | /** | 1769 | /** |
1770 | * Free resources occupied by a destination entry. | ||
1771 | * | ||
1772 | * @param de entry to free | ||
1773 | */ | ||
1774 | static void | ||
1775 | free_destination_entry (struct DestinationEntry *de) | ||
1776 | { | ||
1777 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1778 | "Cleaning up destination entry\n"); | ||
1779 | GNUNET_STATISTICS_update (stats, | ||
1780 | gettext_noop ("# Active destinations"), | ||
1781 | -1, GNUNET_NO); | ||
1782 | if (NULL != de->ts) | ||
1783 | { | ||
1784 | free_tunnel_state (de->ts); | ||
1785 | GNUNET_assert (NULL == de->ts); | ||
1786 | } | ||
1787 | if (NULL != de->heap_node) | ||
1788 | { | ||
1789 | GNUNET_CONTAINER_heap_remove_node (de->heap_node); | ||
1790 | de->heap_node = NULL; | ||
1791 | GNUNET_assert (GNUNET_YES == | ||
1792 | GNUNET_CONTAINER_multihashmap_remove (destination_map, | ||
1793 | &de->key, | ||
1794 | de)); | ||
1795 | } | ||
1796 | GNUNET_free (de); | ||
1797 | } | ||
1798 | |||
1799 | |||
1800 | /** | ||
1801 | * We have too many active destinations. Clean up the oldest destination. | ||
1802 | * | ||
1803 | * @param except destination that must NOT be cleaned up, even if it is the oldest | ||
1804 | */ | ||
1805 | static void | ||
1806 | expire_destination (struct DestinationEntry *except) | ||
1807 | { | ||
1808 | struct DestinationEntry *de; | ||
1809 | |||
1810 | de = GNUNET_CONTAINER_heap_peek (destination_heap); | ||
1811 | if (except == de) | ||
1812 | return; /* can't do this */ | ||
1813 | free_destination_entry (de); | ||
1814 | } | ||
1815 | |||
1816 | |||
1817 | /** | ||
1665 | * A client asks us to setup a redirection via some exit | 1818 | * A client asks us to setup a redirection via some exit |
1666 | * node to a particular IP. Setup the redirection and | 1819 | * node to a particular IP. Setup the redirection and |
1667 | * give the client the allocated IP. | 1820 | * give the client the allocated IP. |
@@ -1807,8 +1960,9 @@ service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *cl | |||
1807 | GNUNET_STATISTICS_update (stats, | 1960 | GNUNET_STATISTICS_update (stats, |
1808 | gettext_noop ("# Active destinations"), | 1961 | gettext_noop ("# Active destinations"), |
1809 | 1, GNUNET_NO); | 1962 | 1, GNUNET_NO); |
1963 | while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings) | ||
1964 | expire_destination (de); | ||
1810 | 1965 | ||
1811 | /* FIXME: expire OLD destinations if we have too many! */ | ||
1812 | /* setup tunnel to destination */ | 1966 | /* setup tunnel to destination */ |
1813 | (void) create_tunnel_to_destination (de, | 1967 | (void) create_tunnel_to_destination (de, |
1814 | (GNUNET_NO == ntohl (msg->nac)) ? NULL : client, | 1968 | (GNUNET_NO == ntohl (msg->nac)) ? NULL : client, |
@@ -1926,7 +2080,8 @@ service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Clien | |||
1926 | de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap, | 2080 | de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap, |
1927 | de, | 2081 | de, |
1928 | GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value); | 2082 | GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value); |
1929 | /* FIXME: expire OLD destinations if we have too many! */ | 2083 | while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings) |
2084 | expire_destination (de); | ||
1930 | (void) create_tunnel_to_destination (de, | 2085 | (void) create_tunnel_to_destination (de, |
1931 | (GNUNET_NO == ntohl (msg->nac)) ? NULL : client, | 2086 | (GNUNET_NO == ntohl (msg->nac)) ? NULL : client, |
1932 | msg->request_id); | 2087 | msg->request_id); |
@@ -1959,104 +2114,6 @@ inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel, | |||
1959 | 2114 | ||
1960 | 2115 | ||
1961 | /** | 2116 | /** |
1962 | * Free resources associated with a tunnel state. | ||
1963 | * | ||
1964 | * @param ts state to free | ||
1965 | */ | ||
1966 | static void | ||
1967 | free_tunnel_state (struct TunnelState *ts) | ||
1968 | { | ||
1969 | GNUNET_HashCode key; | ||
1970 | struct TunnelMessageQueueEntry *tnq; | ||
1971 | |||
1972 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1973 | "Cleaning up tunnel state\n"); | ||
1974 | GNUNET_STATISTICS_update (stats, | ||
1975 | gettext_noop ("# Active tunnels"), | ||
1976 | -1, GNUNET_NO); | ||
1977 | while (NULL != (tnq = ts->tmq_head)) | ||
1978 | { | ||
1979 | GNUNET_CONTAINER_DLL_remove (ts->tmq_head, | ||
1980 | ts->tmq_tail, | ||
1981 | tnq); | ||
1982 | ts->tmq_length--; | ||
1983 | GNUNET_free (tnq); | ||
1984 | } | ||
1985 | GNUNET_assert (0 == ts->tmq_length); | ||
1986 | if (NULL != ts->client) | ||
1987 | { | ||
1988 | GNUNET_SERVER_client_drop (ts->client); | ||
1989 | ts->client = NULL; | ||
1990 | } | ||
1991 | if (NULL != ts->th) | ||
1992 | { | ||
1993 | GNUNET_MESH_notify_transmit_ready_cancel (ts->th); | ||
1994 | ts->th = NULL; | ||
1995 | } | ||
1996 | GNUNET_assert (NULL == ts->destination.heap_node); | ||
1997 | if (NULL != ts->tunnel) | ||
1998 | { | ||
1999 | GNUNET_MESH_tunnel_destroy (ts->tunnel); | ||
2000 | ts->tunnel = NULL; | ||
2001 | } | ||
2002 | if (NULL != ts->heap_node) | ||
2003 | { | ||
2004 | GNUNET_CONTAINER_heap_remove_node (ts->heap_node); | ||
2005 | ts->heap_node = NULL; | ||
2006 | get_tunnel_key_from_ips (ts->af, | ||
2007 | ts->protocol, | ||
2008 | &ts->source_ip, | ||
2009 | ts->source_port, | ||
2010 | &ts->destination_ip, | ||
2011 | ts->destination_port, | ||
2012 | &key); | ||
2013 | GNUNET_assert (GNUNET_YES == | ||
2014 | GNUNET_CONTAINER_multihashmap_remove (tunnel_map, | ||
2015 | &key, | ||
2016 | ts)); | ||
2017 | } | ||
2018 | if (NULL != ts->destination_container) | ||
2019 | { | ||
2020 | GNUNET_assert (ts == ts->destination_container->ts); | ||
2021 | ts->destination_container->ts = NULL; | ||
2022 | ts->destination_container = NULL; | ||
2023 | } | ||
2024 | GNUNET_free (ts); | ||
2025 | } | ||
2026 | |||
2027 | |||
2028 | /** | ||
2029 | * Free resources occupied by a destination entry. | ||
2030 | * | ||
2031 | * @param de entry to free | ||
2032 | */ | ||
2033 | static void | ||
2034 | free_destination_entry (struct DestinationEntry *de) | ||
2035 | { | ||
2036 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2037 | "Cleaning up destination entry\n"); | ||
2038 | GNUNET_STATISTICS_update (stats, | ||
2039 | gettext_noop ("# Active destinations"), | ||
2040 | -1, GNUNET_NO); | ||
2041 | if (NULL != de->ts) | ||
2042 | { | ||
2043 | free_tunnel_state (de->ts); | ||
2044 | GNUNET_assert (NULL == de->ts); | ||
2045 | } | ||
2046 | if (NULL != de->heap_node) | ||
2047 | { | ||
2048 | GNUNET_CONTAINER_heap_remove_node (de->heap_node); | ||
2049 | de->heap_node = NULL; | ||
2050 | GNUNET_assert (GNUNET_YES == | ||
2051 | GNUNET_CONTAINER_multihashmap_remove (destination_map, | ||
2052 | &de->key, | ||
2053 | de)); | ||
2054 | } | ||
2055 | GNUNET_free (de); | ||
2056 | } | ||
2057 | |||
2058 | |||
2059 | /** | ||
2060 | * Function called whenever an inbound tunnel is destroyed. Should clean up | 2117 | * Function called whenever an inbound tunnel is destroyed. Should clean up |
2061 | * any associated state. | 2118 | * any associated state. |
2062 | * | 2119 | * |