diff options
-rw-r--r-- | src/transport/gnunet-service-transport.c | 606 | ||||
-rw-r--r-- | src/transport/plugin_transport_tcp.c | 24 |
2 files changed, 337 insertions, 293 deletions
diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index 6899ef5fb..a8c3b99a9 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c | |||
@@ -23,6 +23,12 @@ | |||
23 | * @brief low-level P2P messaging | 23 | * @brief low-level P2P messaging |
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
25 | * | 25 | * |
26 | * BUGS: | ||
27 | * - bi-directional nature of TCP is not exploited | ||
28 | * - re-validation is broken (triggered only on successful validation, | ||
29 | * does not consider expiration times | ||
30 | * | ||
31 | * | ||
26 | * NOTE: | 32 | * NOTE: |
27 | * - This code uses 'GNUNET_a2s' for debug printing in many places, | 33 | * - This code uses 'GNUNET_a2s' for debug printing in many places, |
28 | * which is technically wrong since it assumes we have IP+Port | 34 | * which is technically wrong since it assumes we have IP+Port |
@@ -444,7 +450,9 @@ struct NeighbourList | |||
444 | 450 | ||
445 | /** | 451 | /** |
446 | * ID of task scheduled to run when we should retry transmitting | 452 | * ID of task scheduled to run when we should retry transmitting |
447 | * the head of the message queue. | 453 | * the head of the message queue. Actually triggered when the |
454 | * transmission is timing out (we trigger instantly when we have | ||
455 | * a chance of success). | ||
448 | */ | 456 | */ |
449 | GNUNET_SCHEDULER_TaskIdentifier retry_task; | 457 | GNUNET_SCHEDULER_TaskIdentifier retry_task; |
450 | 458 | ||
@@ -1082,11 +1090,25 @@ transmit_send_continuation (void *cls, | |||
1082 | mq->specific_address->timeout = | 1090 | mq->specific_address->timeout = |
1083 | GNUNET_TIME_relative_to_absolute | 1091 | GNUNET_TIME_relative_to_absolute |
1084 | (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); | 1092 | (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); |
1085 | mq->specific_address->connected = GNUNET_YES; | 1093 | if (mq->specific_address->connected != GNUNET_YES) |
1094 | { | ||
1095 | GNUNET_STATISTICS_update (stats, | ||
1096 | gettext_noop ("# connected addresses"), | ||
1097 | 1, | ||
1098 | GNUNET_NO); | ||
1099 | mq->specific_address->connected = GNUNET_YES; | ||
1100 | } | ||
1086 | } | 1101 | } |
1087 | else | 1102 | else |
1088 | { | 1103 | { |
1089 | mq->specific_address->connected = GNUNET_NO; | 1104 | if (mq->specific_address->connected != GNUNET_NO) |
1105 | { | ||
1106 | GNUNET_STATISTICS_update (stats, | ||
1107 | gettext_noop ("# connected addresses"), | ||
1108 | -1, | ||
1109 | GNUNET_NO); | ||
1110 | mq->specific_address->connected = GNUNET_NO; | ||
1111 | } | ||
1090 | } | 1112 | } |
1091 | if (! mq->internal_msg) | 1113 | if (! mq->internal_msg) |
1092 | mq->specific_address->in_transmit = GNUNET_NO; | 1114 | mq->specific_address->in_transmit = GNUNET_NO; |
@@ -1129,6 +1151,10 @@ find_ready_address(struct NeighbourList *neighbour) | |||
1129 | "Marking long-time inactive connection to `%4s' as down.\n", | 1151 | "Marking long-time inactive connection to `%4s' as down.\n", |
1130 | GNUNET_i2s (&neighbour->id)); | 1152 | GNUNET_i2s (&neighbour->id)); |
1131 | #endif | 1153 | #endif |
1154 | GNUNET_STATISTICS_update (stats, | ||
1155 | gettext_noop ("# connected addresses"), | ||
1156 | -1, | ||
1157 | GNUNET_NO); | ||
1132 | addresses->connected = GNUNET_NO; | 1158 | addresses->connected = GNUNET_NO; |
1133 | } | 1159 | } |
1134 | addresses = addresses->next; | 1160 | addresses = addresses->next; |
@@ -1150,14 +1176,21 @@ find_ready_address(struct NeighbourList *neighbour) | |||
1150 | } | 1176 | } |
1151 | head = head->next; | 1177 | head = head->next; |
1152 | } | 1178 | } |
1153 | #if DEBUG_TRANSPORT | ||
1154 | if (best_address != NULL) | 1179 | if (best_address != NULL) |
1155 | { | 1180 | { |
1181 | #if DEBUG_TRANSPORT | ||
1156 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1182 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1157 | "Best address found has latency of %llu ms.\n", | 1183 | "Best address found has latency of %llu ms.\n", |
1158 | best_address->latency.value); | 1184 | best_address->latency.value); |
1159 | } | ||
1160 | #endif | 1185 | #endif |
1186 | } | ||
1187 | else | ||
1188 | { | ||
1189 | GNUNET_STATISTICS_update (stats, | ||
1190 | gettext_noop ("# transmission attempts failed (no validated address)"), | ||
1191 | 1, | ||
1192 | GNUNET_NO); | ||
1193 | } | ||
1161 | return best_address; | 1194 | return best_address; |
1162 | 1195 | ||
1163 | } | 1196 | } |
@@ -1225,6 +1258,10 @@ try_transmission_to_peer (struct NeighbourList *neighbour) | |||
1225 | GNUNET_free (mq); | 1258 | GNUNET_free (mq); |
1226 | return; /* nobody ready */ | 1259 | return; /* nobody ready */ |
1227 | } | 1260 | } |
1261 | GNUNET_STATISTICS_update (stats, | ||
1262 | gettext_noop ("# message delivery deferred (no validated address)"), | ||
1263 | 1, | ||
1264 | GNUNET_NO); | ||
1228 | if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK) | 1265 | if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK) |
1229 | GNUNET_SCHEDULER_cancel (sched, | 1266 | GNUNET_SCHEDULER_cancel (sched, |
1230 | neighbour->retry_task); | 1267 | neighbour->retry_task); |
@@ -1784,184 +1821,91 @@ add_validated_address (void *cls, | |||
1784 | } | 1821 | } |
1785 | 1822 | ||
1786 | 1823 | ||
1787 | static void send_periodic_ping(void *cls, | 1824 | |
1788 | const struct GNUNET_SCHEDULER_TaskContext *tc); | 1825 | /** |
1826 | * Closure for 'check_address_exists'. | ||
1827 | */ | ||
1828 | struct CheckAddressExistsClosure | ||
1829 | { | ||
1830 | /** | ||
1831 | * Address to check for. | ||
1832 | */ | ||
1833 | const void *addr; | ||
1834 | |||
1835 | /** | ||
1836 | * Name of the transport. | ||
1837 | */ | ||
1838 | const char *tname; | ||
1839 | |||
1840 | /** | ||
1841 | * Length of addr. | ||
1842 | */ | ||
1843 | size_t addrlen; | ||
1844 | |||
1845 | /** | ||
1846 | * Set to GNUNET_YES if the address exists. | ||
1847 | */ | ||
1848 | int exists; | ||
1849 | }; | ||
1789 | 1850 | ||
1790 | 1851 | ||
1791 | /** | 1852 | /** |
1792 | * Iterator over hash map entries. Checks if the given validation | 1853 | * Iterator over hash map entries. Checks if the given |
1793 | * entry is for the same challenge as what is given in the PONG. | 1854 | * validation entry is for the same address as what is given |
1855 | * in the closure. | ||
1794 | * | 1856 | * |
1795 | * @param cls the 'struct TransportPongMessage*' | 1857 | * @param cls the 'struct CheckAddressExistsClosure*' |
1796 | * @param key peer identity | 1858 | * @param key current key code (ignored) |
1797 | * @param value value in the hash map ('struct ValidationEntry') | 1859 | * @param value value in the hash map ('struct ValidationEntry') |
1798 | * @return GNUNET_YES if we should continue to | 1860 | * @return GNUNET_YES if we should continue to |
1799 | * iterate (mismatch), GNUNET_NO if not (entry matched) | 1861 | * iterate (mismatch), GNUNET_NO if not (entry matched) |
1800 | */ | 1862 | */ |
1801 | static int | 1863 | static int |
1802 | check_pending_validation (void *cls, | 1864 | check_address_exists (void *cls, |
1803 | const GNUNET_HashCode * key, | 1865 | const GNUNET_HashCode * key, |
1804 | void *value) | 1866 | void *value) |
1805 | { | 1867 | { |
1806 | const struct TransportPongMessage *pong = cls; | 1868 | struct CheckAddressExistsClosure *caec = cls; |
1807 | struct ValidationEntry *ve = value; | 1869 | struct ValidationEntry *ve = value; |
1808 | struct AddValidatedAddressContext avac; | 1870 | if ( (0 == strcmp (caec->tname, |
1809 | unsigned int challenge = ntohl(pong->challenge); | 1871 | ve->transport_name)) && |
1810 | struct GNUNET_HELLO_Message *hello; | 1872 | (caec->addrlen == ve->addrlen) && |
1811 | struct GNUNET_PeerIdentity target; | 1873 | (0 == memcmp (caec->addr, |
1812 | struct NeighbourList *n; | 1874 | ve->addr, |
1813 | struct ForeignAddressList *fal; | 1875 | caec->addrlen)) ) |
1814 | struct PeriodicValidationContext *periodic_validation_context; | ||
1815 | |||
1816 | if (ve->challenge != challenge) | ||
1817 | return GNUNET_YES; | ||
1818 | |||
1819 | #if DEBUG_TRANSPORT | ||
1820 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1821 | "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n", | ||
1822 | GNUNET_h2s (key), | ||
1823 | GNUNET_a2s ((const struct sockaddr *) ve->addr, | ||
1824 | ve->addrlen), | ||
1825 | ve->transport_name); | ||
1826 | #endif | ||
1827 | GNUNET_STATISTICS_update (stats, | ||
1828 | gettext_noop ("# address validation successes"), | ||
1829 | 1, | ||
1830 | GNUNET_NO); | ||
1831 | /* create the updated HELLO */ | ||
1832 | GNUNET_CRYPTO_hash (&ve->publicKey, | ||
1833 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
1834 | &target.hashPubKey); | ||
1835 | avac.done = GNUNET_NO; | ||
1836 | avac.ve = ve; | ||
1837 | hello = GNUNET_HELLO_create (&ve->publicKey, | ||
1838 | &add_validated_address, | ||
1839 | &avac); | ||
1840 | GNUNET_PEERINFO_add_peer (cfg, sched, | ||
1841 | &target, | ||
1842 | hello); | ||
1843 | GNUNET_free (hello); | ||
1844 | n = find_neighbour (&target); | ||
1845 | if (n != NULL) | ||
1846 | { | 1876 | { |
1847 | fal = add_peer_address (n, | 1877 | caec->exists = GNUNET_YES; |
1848 | ve->transport_name, | 1878 | return GNUNET_NO; |
1849 | ve->addr, | ||
1850 | ve->addrlen); | ||
1851 | GNUNET_assert (fal != NULL); | ||
1852 | fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION); | ||
1853 | fal->validated = GNUNET_YES; | ||
1854 | fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time); | ||
1855 | periodic_validation_context = GNUNET_malloc(sizeof(struct PeriodicValidationContext)); | ||
1856 | periodic_validation_context->foreign_address = fal; | ||
1857 | periodic_validation_context->transport = strdup(ve->transport_name); | ||
1858 | memcpy(&periodic_validation_context->publicKey, | ||
1859 | &ve->publicKey, | ||
1860 | sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); | ||
1861 | /* FIXME: this causes all of the revalidation PINGs for the same HELLO | ||
1862 | to be transmitted in bulk, which is not nice; also, | ||
1863 | triggering these HERE means that revalidations do NOT happen AT ALL | ||
1864 | for HELLOs a previous instance of this process validated (since | ||
1865 | there is no "initial" validation PING => no revalidation => BUG! */ | ||
1866 | fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched, | ||
1867 | TRANSPORT_DEFAULT_REVALIDATION, | ||
1868 | &send_periodic_ping, | ||
1869 | periodic_validation_context); | ||
1870 | if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value) | ||
1871 | n->latency = fal->latency; | ||
1872 | else | ||
1873 | n->latency.value = (fal->latency.value + n->latency.value) / 2; | ||
1874 | n->distance = fal->distance; | ||
1875 | if (GNUNET_NO == n->received_pong) | ||
1876 | { | ||
1877 | notify_clients_connect (&target, n->latency, n->distance); | ||
1878 | n->received_pong = GNUNET_YES; | ||
1879 | } | ||
1880 | if (n->retry_task != GNUNET_SCHEDULER_NO_TASK) | ||
1881 | { | ||
1882 | GNUNET_SCHEDULER_cancel (sched, | ||
1883 | n->retry_task); | ||
1884 | n->retry_task = GNUNET_SCHEDULER_NO_TASK; | ||
1885 | try_transmission_to_peer (n); | ||
1886 | } | ||
1887 | } | 1879 | } |
1888 | 1880 | return GNUNET_YES; | |
1889 | /* clean up validation entry */ | ||
1890 | GNUNET_assert (GNUNET_YES == | ||
1891 | GNUNET_CONTAINER_multihashmap_remove (validation_map, | ||
1892 | key, | ||
1893 | ve)); | ||
1894 | GNUNET_SCHEDULER_cancel (sched, | ||
1895 | ve->timeout_task); | ||
1896 | GNUNET_free (ve->transport_name); | ||
1897 | GNUNET_free (ve); | ||
1898 | return GNUNET_NO; | ||
1899 | } | 1881 | } |
1900 | 1882 | ||
1901 | 1883 | ||
1902 | /** | 1884 | /** |
1903 | * Function that will be called if we receive a validation | 1885 | * HELLO validation cleanup task (validation failed). |
1904 | * of an address challenge that we transmitted to another | ||
1905 | * peer. Note that the validation should only be considered | ||
1906 | * acceptable if the challenge matches AND if the sender | ||
1907 | * address is at least a plausible address for this peer | ||
1908 | * (otherwise we may be seeing a MiM attack). | ||
1909 | * | 1886 | * |
1910 | * @param cls closure | 1887 | * @param cls the 'struct ValidationEntry' that failed |
1911 | * @param message the pong message | 1888 | * @param tc scheduler context (unused) |
1912 | * @param peer who responded to our challenge | ||
1913 | * @param sender_address string describing our sender address (as observed | ||
1914 | * by the other peer in binary format) | ||
1915 | * @param sender_address_len number of bytes in 'sender_address' | ||
1916 | */ | 1889 | */ |
1917 | static void | 1890 | static void |
1918 | handle_pong (void *cls, const struct GNUNET_MessageHeader *message, | 1891 | timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
1919 | const struct GNUNET_PeerIdentity *peer, | ||
1920 | const char *sender_address, | ||
1921 | size_t sender_address_len) | ||
1922 | { | 1892 | { |
1923 | #if DEBUG_TRANSPORT > 1 | 1893 | struct ValidationEntry *va = cls; |
1924 | /* we get tons of these that just get discarded, only log | 1894 | struct GNUNET_PeerIdentity pid; |
1925 | if we are quite verbose */ | 1895 | |
1926 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1927 | "Receiving `%s' message from `%4s'.\n", "PONG", | ||
1928 | GNUNET_i2s (peer)); | ||
1929 | #endif | ||
1930 | GNUNET_STATISTICS_update (stats, | 1896 | GNUNET_STATISTICS_update (stats, |
1931 | gettext_noop ("# PONG messages received"), | 1897 | gettext_noop ("# address validation timeouts"), |
1932 | 1, | 1898 | 1, |
1933 | GNUNET_NO); | 1899 | GNUNET_NO); |
1934 | if (GNUNET_SYSERR != | 1900 | GNUNET_CRYPTO_hash (&va->publicKey, |
1935 | GNUNET_CONTAINER_multihashmap_get_multiple (validation_map, | 1901 | sizeof (struct |
1936 | &peer->hashPubKey, | 1902 | GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), |
1937 | &check_pending_validation, | 1903 | &pid.hashPubKey); |
1938 | (void*) message)) | 1904 | GNUNET_CONTAINER_multihashmap_remove (validation_map, |
1939 | { | 1905 | &pid.hashPubKey, |
1940 | /* This is *expected* to happen a lot since we send | 1906 | va); |
1941 | PONGs to *all* known addresses of the sender of | 1907 | GNUNET_free (va->transport_name); |
1942 | the PING, so most likely we get multiple PONGs | 1908 | GNUNET_free (va); |
1943 | per PING, and all but the first PONG will end up | ||
1944 | here. So really we should not print anything here | ||
1945 | unless we want to be very, very verbose... */ | ||
1946 | #if DEBUG_TRANSPORT > 2 | ||
1947 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1948 | "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n", | ||
1949 | "PONG", | ||
1950 | GNUNET_i2s (peer), | ||
1951 | "PING"); | ||
1952 | #endif | ||
1953 | return; | ||
1954 | } | ||
1955 | |||
1956 | #if 0 | ||
1957 | /* FIXME: add given address to potential pool of our addresses | ||
1958 | (for voting) */ | ||
1959 | GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, | ||
1960 | _("Another peer saw us using the address `%s' via `%s'.\n"), | ||
1961 | GNUNET_a2s ((const struct sockaddr *) &pong[1], | ||
1962 | ntohs(pong->addrlen)), | ||
1963 | va->transport_name); | ||
1964 | #endif | ||
1965 | } | 1909 | } |
1966 | 1910 | ||
1967 | 1911 | ||
@@ -2000,6 +1944,10 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer) | |||
2000 | struct ReadyList *rl; | 1944 | struct ReadyList *rl; |
2001 | 1945 | ||
2002 | GNUNET_assert (our_hello != NULL); | 1946 | GNUNET_assert (our_hello != NULL); |
1947 | GNUNET_STATISTICS_update (stats, | ||
1948 | gettext_noop ("# active neighbours"), | ||
1949 | 1, | ||
1950 | GNUNET_NO); | ||
2003 | n = GNUNET_malloc (sizeof (struct NeighbourList)); | 1951 | n = GNUNET_malloc (sizeof (struct NeighbourList)); |
2004 | n->next = neighbours; | 1952 | n->next = neighbours; |
2005 | neighbours = n; | 1953 | neighbours = n; |
@@ -2037,123 +1985,38 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer) | |||
2037 | 1985 | ||
2038 | 1986 | ||
2039 | /** | 1987 | /** |
2040 | * Closure for 'check_address_exists'. | 1988 | * Send periodic PING messages to a give foreign address. |
2041 | */ | ||
2042 | struct CheckAddressExistsClosure | ||
2043 | { | ||
2044 | /** | ||
2045 | * Address to check for. | ||
2046 | */ | ||
2047 | const void *addr; | ||
2048 | |||
2049 | /** | ||
2050 | * Name of the transport. | ||
2051 | */ | ||
2052 | const char *tname; | ||
2053 | |||
2054 | /** | ||
2055 | * Length of addr. | ||
2056 | */ | ||
2057 | size_t addrlen; | ||
2058 | |||
2059 | /** | ||
2060 | * Set to GNUNET_YES if the address exists. | ||
2061 | */ | ||
2062 | int exists; | ||
2063 | }; | ||
2064 | |||
2065 | |||
2066 | /** | ||
2067 | * Iterator over hash map entries. Checks if the given | ||
2068 | * validation entry is for the same address as what is given | ||
2069 | * in the closure. | ||
2070 | * | ||
2071 | * @param cls the 'struct CheckAddressExistsClosure*' | ||
2072 | * @param key current key code (ignored) | ||
2073 | * @param value value in the hash map ('struct ValidationEntry') | ||
2074 | * @return GNUNET_YES if we should continue to | ||
2075 | * iterate (mismatch), GNUNET_NO if not (entry matched) | ||
2076 | */ | ||
2077 | static int | ||
2078 | check_address_exists (void *cls, | ||
2079 | const GNUNET_HashCode * key, | ||
2080 | void *value) | ||
2081 | { | ||
2082 | struct CheckAddressExistsClosure *caec = cls; | ||
2083 | struct ValidationEntry *ve = value; | ||
2084 | if ( (0 == strcmp (caec->tname, | ||
2085 | ve->transport_name)) && | ||
2086 | (caec->addrlen == ve->addrlen) && | ||
2087 | (0 == memcmp (caec->addr, | ||
2088 | ve->addr, | ||
2089 | caec->addrlen)) ) | ||
2090 | { | ||
2091 | caec->exists = GNUNET_YES; | ||
2092 | return GNUNET_NO; | ||
2093 | } | ||
2094 | return GNUNET_YES; | ||
2095 | } | ||
2096 | |||
2097 | |||
2098 | /** | ||
2099 | * HELLO validation cleanup task (validation failed). | ||
2100 | * | 1989 | * |
2101 | * @param cls the 'struct ValidationEntry' that failed | 1990 | * @param cls our 'struct PeriodicValidationContext*' |
2102 | * @param tc scheduler context (unused) | 1991 | * @param tc task context |
2103 | */ | 1992 | */ |
2104 | static void | 1993 | static void |
2105 | timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 1994 | send_periodic_ping (void *cls, |
2106 | { | 1995 | const struct GNUNET_SCHEDULER_TaskContext *tc) |
2107 | struct ValidationEntry *va = cls; | ||
2108 | struct GNUNET_PeerIdentity pid; | ||
2109 | |||
2110 | GNUNET_STATISTICS_update (stats, | ||
2111 | gettext_noop ("# address validation timeouts"), | ||
2112 | 1, | ||
2113 | GNUNET_NO); | ||
2114 | GNUNET_CRYPTO_hash (&va->publicKey, | ||
2115 | sizeof (struct | ||
2116 | GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
2117 | &pid.hashPubKey); | ||
2118 | GNUNET_CONTAINER_multihashmap_remove (validation_map, | ||
2119 | &pid.hashPubKey, | ||
2120 | va); | ||
2121 | GNUNET_free (va->transport_name); | ||
2122 | GNUNET_free (va); | ||
2123 | } | ||
2124 | |||
2125 | |||
2126 | /** | ||
2127 | * Check if the given address is already being validated; if not, | ||
2128 | * append the given address to the list of entries that are being be | ||
2129 | * validated and initiate validation. | ||
2130 | * | ||
2131 | * @param cls closure ('struct PeriodicValidationContext *') | ||
2132 | * @param tname name of the transport | ||
2133 | * @param expiration expiration time | ||
2134 | * @param addr the address | ||
2135 | * @param addrlen length of the address | ||
2136 | * @return GNUNET_OK (always) | ||
2137 | */ | ||
2138 | static int | ||
2139 | rerun_validation (void *cls, | ||
2140 | const char *tname, | ||
2141 | struct GNUNET_TIME_Absolute expiration, | ||
2142 | const void *addr, size_t addrlen) | ||
2143 | { | 1996 | { |
2144 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey = cls; | 1997 | struct PeriodicValidationContext *pvc = cls; |
1998 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey = pvc->publicKey; | ||
1999 | char *tname = pvc->transport; | ||
2000 | const void *addr = pvc->foreign_address->addr; | ||
2001 | size_t addrlen = pvc->foreign_address->addrlen; | ||
2145 | struct GNUNET_PeerIdentity id; | 2002 | struct GNUNET_PeerIdentity id; |
2146 | struct TransportPlugin *tp; | 2003 | struct TransportPlugin *tp; |
2147 | struct ValidationEntry *va; | 2004 | struct ValidationEntry *va; |
2148 | struct NeighbourList *neighbour; | 2005 | struct NeighbourList *neighbour; |
2149 | struct ForeignAddressList *peer_address; | 2006 | struct ForeignAddressList *peer_address; |
2150 | struct TransportPingMessage ping; | 2007 | struct TransportPingMessage ping; |
2151 | /*struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;*/ | ||
2152 | struct CheckAddressExistsClosure caec; | 2008 | struct CheckAddressExistsClosure caec; |
2153 | char * message_buf; | 2009 | char * message_buf; |
2154 | uint16_t hello_size; | 2010 | uint16_t hello_size; |
2155 | size_t tsize; | 2011 | size_t tsize; |
2156 | 2012 | ||
2013 | GNUNET_free (pvc); | ||
2014 | if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) | ||
2015 | { | ||
2016 | /* We have been shutdown, don't do anything! */ | ||
2017 | GNUNET_free (tname); | ||
2018 | return; | ||
2019 | } | ||
2157 | tp = find_transport (tname); | 2020 | tp = find_transport (tname); |
2158 | if (tp == NULL) | 2021 | if (tp == NULL) |
2159 | { | 2022 | { |
@@ -2162,10 +2025,11 @@ rerun_validation (void *cls, | |||
2162 | _ | 2025 | _ |
2163 | ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"), | 2026 | ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"), |
2164 | tname); | 2027 | tname); |
2165 | return GNUNET_OK; | 2028 | GNUNET_free (tname); |
2029 | return; | ||
2166 | } | 2030 | } |
2167 | 2031 | ||
2168 | GNUNET_CRYPTO_hash (publicKey, | 2032 | GNUNET_CRYPTO_hash (&publicKey, |
2169 | sizeof (struct | 2033 | sizeof (struct |
2170 | GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | 2034 | GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), |
2171 | &id.hashPubKey); | 2035 | &id.hashPubKey); |
@@ -2189,17 +2053,18 @@ rerun_validation (void *cls, | |||
2189 | tname, | 2053 | tname, |
2190 | GNUNET_i2s (&id)); | 2054 | GNUNET_i2s (&id)); |
2191 | #endif | 2055 | #endif |
2192 | return GNUNET_OK; | 2056 | GNUNET_free (tname); |
2057 | return; | ||
2193 | } | 2058 | } |
2194 | va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen); | 2059 | va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen); |
2195 | va->transport_name = GNUNET_strdup (tname); | 2060 | va->transport_name = tname; |
2196 | va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | 2061 | va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, |
2197 | (unsigned int) -1); | 2062 | (unsigned int) -1); |
2198 | va->send_time = GNUNET_TIME_absolute_get(); | 2063 | va->send_time = GNUNET_TIME_absolute_get(); |
2199 | va->addr = (const void*) &va[1]; | 2064 | va->addr = (const void*) &va[1]; |
2200 | memcpy (&va[1], addr, addrlen); | 2065 | memcpy (&va[1], addr, addrlen); |
2201 | va->addrlen = addrlen; | 2066 | va->addrlen = addrlen; |
2202 | memcpy(&va->publicKey, publicKey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); | 2067 | memcpy(&va->publicKey, &publicKey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); |
2203 | va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched, | 2068 | va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched, |
2204 | HELLO_VERIFICATION_TIMEOUT, | 2069 | HELLO_VERIFICATION_TIMEOUT, |
2205 | &timeout_hello_validation, | 2070 | &timeout_hello_validation, |
@@ -2243,40 +2108,183 @@ rerun_validation (void *cls, | |||
2243 | message_buf, tsize, | 2108 | message_buf, tsize, |
2244 | GNUNET_YES, neighbour); | 2109 | GNUNET_YES, neighbour); |
2245 | GNUNET_free(message_buf); | 2110 | GNUNET_free(message_buf); |
2246 | return GNUNET_OK; | ||
2247 | } | 2111 | } |
2248 | 2112 | ||
2249 | 2113 | ||
2250 | /** | 2114 | /** |
2251 | * Send periodic ping messages to a give foreign address. | 2115 | * Iterator over hash map entries. Checks if the given validation |
2252 | * | 2116 | * entry is for the same challenge as what is given in the PONG. |
2253 | * cls closure, can be safely cast to ForeignAddressList | ||
2254 | * tc task context | ||
2255 | * | 2117 | * |
2256 | * FIXME: Since a _billion_ pongs are sent for every ping, | 2118 | * @param cls the 'struct TransportPongMessage*' |
2257 | * maybe this should be a special message type or something | 2119 | * @param key peer identity |
2258 | * that gets discarded on the other side instead of initiating | 2120 | * @param value value in the hash map ('struct ValidationEntry') |
2259 | * a flood. | 2121 | * @return GNUNET_YES if we should continue to |
2122 | * iterate (mismatch), GNUNET_NO if not (entry matched) | ||
2260 | */ | 2123 | */ |
2261 | static void | 2124 | static int |
2262 | send_periodic_ping (void *cls, | 2125 | check_pending_validation (void *cls, |
2263 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 2126 | const GNUNET_HashCode * key, |
2127 | void *value) | ||
2264 | { | 2128 | { |
2265 | struct PeriodicValidationContext *periodic_validation_context = cls; | 2129 | const struct TransportPongMessage *pong = cls; |
2130 | struct ValidationEntry *ve = value; | ||
2131 | struct AddValidatedAddressContext avac; | ||
2132 | unsigned int challenge = ntohl(pong->challenge); | ||
2133 | struct GNUNET_HELLO_Message *hello; | ||
2134 | struct GNUNET_PeerIdentity target; | ||
2135 | struct NeighbourList *n; | ||
2136 | struct ForeignAddressList *fal; | ||
2137 | struct PeriodicValidationContext *periodic_validation_context; | ||
2266 | 2138 | ||
2267 | if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) | 2139 | if (ve->challenge != challenge) |
2140 | return GNUNET_YES; | ||
2141 | |||
2142 | #if DEBUG_TRANSPORT | ||
2143 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2144 | "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n", | ||
2145 | GNUNET_h2s (key), | ||
2146 | GNUNET_a2s ((const struct sockaddr *) ve->addr, | ||
2147 | ve->addrlen), | ||
2148 | ve->transport_name); | ||
2149 | #endif | ||
2150 | GNUNET_STATISTICS_update (stats, | ||
2151 | gettext_noop ("# address validation successes"), | ||
2152 | 1, | ||
2153 | GNUNET_NO); | ||
2154 | /* create the updated HELLO */ | ||
2155 | GNUNET_CRYPTO_hash (&ve->publicKey, | ||
2156 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
2157 | &target.hashPubKey); | ||
2158 | avac.done = GNUNET_NO; | ||
2159 | avac.ve = ve; | ||
2160 | hello = GNUNET_HELLO_create (&ve->publicKey, | ||
2161 | &add_validated_address, | ||
2162 | &avac); | ||
2163 | GNUNET_PEERINFO_add_peer (cfg, sched, | ||
2164 | &target, | ||
2165 | hello); | ||
2166 | GNUNET_free (hello); | ||
2167 | n = find_neighbour (&target); | ||
2168 | if (n != NULL) | ||
2268 | { | 2169 | { |
2269 | GNUNET_free(periodic_validation_context->transport); | 2170 | fal = add_peer_address (n, |
2270 | GNUNET_free(periodic_validation_context); | 2171 | ve->transport_name, |
2271 | return; /* We have been shutdown, don't do anything! */ | 2172 | ve->addr, |
2272 | } | 2173 | ve->addrlen); |
2273 | rerun_validation(&periodic_validation_context->publicKey, | 2174 | GNUNET_assert (fal != NULL); |
2274 | periodic_validation_context->transport, | 2175 | fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION); |
2275 | periodic_validation_context->foreign_address->expires, | 2176 | fal->validated = GNUNET_YES; |
2276 | periodic_validation_context->foreign_address->addr, | 2177 | fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time); |
2277 | periodic_validation_context->foreign_address->addrlen); | 2178 | periodic_validation_context = GNUNET_malloc(sizeof(struct PeriodicValidationContext)); |
2278 | GNUNET_free(periodic_validation_context->transport); | 2179 | periodic_validation_context->foreign_address = fal; |
2279 | GNUNET_free(periodic_validation_context); | 2180 | periodic_validation_context->transport = strdup(ve->transport_name); |
2181 | memcpy(&periodic_validation_context->publicKey, | ||
2182 | &ve->publicKey, | ||
2183 | sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); | ||
2184 | /* FIXME: this causes all of the revalidation PINGs for the same HELLO | ||
2185 | to be transmitted in bulk, which is not nice; also, | ||
2186 | triggering these HERE means that revalidations do NOT happen AT ALL | ||
2187 | for HELLOs a previous instance of this process validated (since | ||
2188 | there is no "initial" validation PING => no revalidation => BUG! */ | ||
2189 | fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched, | ||
2190 | TRANSPORT_DEFAULT_REVALIDATION, | ||
2191 | &send_periodic_ping, | ||
2192 | periodic_validation_context); | ||
2193 | if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value) | ||
2194 | n->latency = fal->latency; | ||
2195 | else | ||
2196 | n->latency.value = (fal->latency.value + n->latency.value) / 2; | ||
2197 | n->distance = fal->distance; | ||
2198 | if (GNUNET_NO == n->received_pong) | ||
2199 | { | ||
2200 | notify_clients_connect (&target, n->latency, n->distance); | ||
2201 | n->received_pong = GNUNET_YES; | ||
2202 | } | ||
2203 | if (n->retry_task != GNUNET_SCHEDULER_NO_TASK) | ||
2204 | { | ||
2205 | GNUNET_SCHEDULER_cancel (sched, | ||
2206 | n->retry_task); | ||
2207 | n->retry_task = GNUNET_SCHEDULER_NO_TASK; | ||
2208 | try_transmission_to_peer (n); | ||
2209 | } | ||
2210 | } | ||
2211 | |||
2212 | /* clean up validation entry */ | ||
2213 | GNUNET_assert (GNUNET_YES == | ||
2214 | GNUNET_CONTAINER_multihashmap_remove (validation_map, | ||
2215 | key, | ||
2216 | ve)); | ||
2217 | GNUNET_SCHEDULER_cancel (sched, | ||
2218 | ve->timeout_task); | ||
2219 | GNUNET_free (ve->transport_name); | ||
2220 | GNUNET_free (ve); | ||
2221 | return GNUNET_NO; | ||
2222 | } | ||
2223 | |||
2224 | |||
2225 | /** | ||
2226 | * Function that will be called if we receive a validation | ||
2227 | * of an address challenge that we transmitted to another | ||
2228 | * peer. Note that the validation should only be considered | ||
2229 | * acceptable if the challenge matches AND if the sender | ||
2230 | * address is at least a plausible address for this peer | ||
2231 | * (otherwise we may be seeing a MiM attack). | ||
2232 | * | ||
2233 | * @param cls closure | ||
2234 | * @param message the pong message | ||
2235 | * @param peer who responded to our challenge | ||
2236 | * @param sender_address string describing our sender address (as observed | ||
2237 | * by the other peer in binary format) | ||
2238 | * @param sender_address_len number of bytes in 'sender_address' | ||
2239 | */ | ||
2240 | static void | ||
2241 | handle_pong (void *cls, const struct GNUNET_MessageHeader *message, | ||
2242 | const struct GNUNET_PeerIdentity *peer, | ||
2243 | const char *sender_address, | ||
2244 | size_t sender_address_len) | ||
2245 | { | ||
2246 | #if DEBUG_TRANSPORT > 1 | ||
2247 | /* we get tons of these that just get discarded, only log | ||
2248 | if we are quite verbose */ | ||
2249 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2250 | "Receiving `%s' message from `%4s'.\n", "PONG", | ||
2251 | GNUNET_i2s (peer)); | ||
2252 | #endif | ||
2253 | GNUNET_STATISTICS_update (stats, | ||
2254 | gettext_noop ("# PONG messages received"), | ||
2255 | 1, | ||
2256 | GNUNET_NO); | ||
2257 | if (GNUNET_SYSERR != | ||
2258 | GNUNET_CONTAINER_multihashmap_get_multiple (validation_map, | ||
2259 | &peer->hashPubKey, | ||
2260 | &check_pending_validation, | ||
2261 | (void*) message)) | ||
2262 | { | ||
2263 | /* This is *expected* to happen a lot since we send | ||
2264 | PONGs to *all* known addresses of the sender of | ||
2265 | the PING, so most likely we get multiple PONGs | ||
2266 | per PING, and all but the first PONG will end up | ||
2267 | here. So really we should not print anything here | ||
2268 | unless we want to be very, very verbose... */ | ||
2269 | #if DEBUG_TRANSPORT > 2 | ||
2270 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2271 | "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n", | ||
2272 | "PONG", | ||
2273 | GNUNET_i2s (peer), | ||
2274 | "PING"); | ||
2275 | #endif | ||
2276 | return; | ||
2277 | } | ||
2278 | |||
2279 | #if 0 | ||
2280 | /* FIXME: add given address to potential pool of our addresses | ||
2281 | (for voting) */ | ||
2282 | GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, | ||
2283 | _("Another peer saw us using the address `%s' via `%s'.\n"), | ||
2284 | GNUNET_a2s ((const struct sockaddr *) &pong[1], | ||
2285 | ntohs(pong->addrlen)), | ||
2286 | va->transport_name); | ||
2287 | #endif | ||
2280 | } | 2288 | } |
2281 | 2289 | ||
2282 | 2290 | ||
@@ -2698,11 +2706,15 @@ disconnect_neighbour (struct NeighbourList *n, int check) | |||
2698 | { | 2706 | { |
2699 | n->plugins = rpos->next; | 2707 | n->plugins = rpos->next; |
2700 | rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id); | 2708 | rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id); |
2701 | |||
2702 | while (rpos->addresses != NULL) | 2709 | while (rpos->addresses != NULL) |
2703 | { | 2710 | { |
2704 | peer_pos = rpos->addresses; | 2711 | peer_pos = rpos->addresses; |
2705 | rpos->addresses = peer_pos->next; | 2712 | rpos->addresses = peer_pos->next; |
2713 | if (peer_pos->connected == GNUNET_YES) | ||
2714 | GNUNET_STATISTICS_update (stats, | ||
2715 | gettext_noop ("# connected addresses"), | ||
2716 | -1, | ||
2717 | GNUNET_NO); | ||
2706 | GNUNET_free(peer_pos); | 2718 | GNUNET_free(peer_pos); |
2707 | } | 2719 | } |
2708 | GNUNET_free (rpos); | 2720 | GNUNET_free (rpos); |
@@ -2738,6 +2750,10 @@ disconnect_neighbour (struct NeighbourList *n, int check) | |||
2738 | n->retry_task = GNUNET_SCHEDULER_NO_TASK; | 2750 | n->retry_task = GNUNET_SCHEDULER_NO_TASK; |
2739 | } | 2751 | } |
2740 | /* finally, free n itself */ | 2752 | /* finally, free n itself */ |
2753 | GNUNET_STATISTICS_update (stats, | ||
2754 | gettext_noop ("# active neighbours"), | ||
2755 | -1, | ||
2756 | GNUNET_NO); | ||
2741 | GNUNET_free (n); | 2757 | GNUNET_free (n); |
2742 | } | 2758 | } |
2743 | 2759 | ||
@@ -2884,6 +2900,10 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer, | |||
2884 | { | 2900 | { |
2885 | peer_address->connected = GNUNET_YES; | 2901 | peer_address->connected = GNUNET_YES; |
2886 | peer_address->connect_attempts++; | 2902 | peer_address->connect_attempts++; |
2903 | GNUNET_STATISTICS_update (stats, | ||
2904 | gettext_noop ("# connected addresses"), | ||
2905 | 1, | ||
2906 | GNUNET_NO); | ||
2887 | } | 2907 | } |
2888 | peer_address->timeout | 2908 | peer_address->timeout |
2889 | = | 2909 | = |
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index a08d98625..e1bb0c7e9 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c | |||
@@ -308,6 +308,10 @@ create_session (struct Plugin *plugin, | |||
308 | welcome.clientIdentity = *plugin->env->my_identity; | 308 | welcome.clientIdentity = *plugin->env->my_identity; |
309 | memcpy (&pm[1], &welcome, sizeof (welcome)); | 309 | memcpy (&pm[1], &welcome, sizeof (welcome)); |
310 | pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; | 310 | pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; |
311 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
312 | gettext_noop ("# bytes currently in TCP buffers"), | ||
313 | pm->message_size, | ||
314 | GNUNET_NO); | ||
311 | GNUNET_CONTAINER_DLL_insert (ret->pending_messages_head, | 315 | GNUNET_CONTAINER_DLL_insert (ret->pending_messages_head, |
312 | ret->pending_messages_tail, | 316 | ret->pending_messages_tail, |
313 | pm); | 317 | pm); |
@@ -370,6 +374,10 @@ do_transmit (void *cls, size_t size, void *buf) | |||
370 | pm->message_size, | 374 | pm->message_size, |
371 | GNUNET_i2s (&session->target)); | 375 | GNUNET_i2s (&session->target)); |
372 | #endif | 376 | #endif |
377 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
378 | gettext_noop ("# bytes currently in TCP buffers"), | ||
379 | -pm->message_size, | ||
380 | GNUNET_NO); | ||
373 | GNUNET_STATISTICS_update (session->plugin->env->stats, | 381 | GNUNET_STATISTICS_update (session->plugin->env->stats, |
374 | gettext_noop ("# bytes discarded by TCP (timeout)"), | 382 | gettext_noop ("# bytes discarded by TCP (timeout)"), |
375 | pm->message_size, | 383 | pm->message_size, |
@@ -394,6 +402,10 @@ do_transmit (void *cls, size_t size, void *buf) | |||
394 | GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, | 402 | GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, |
395 | session->pending_messages_tail, | 403 | session->pending_messages_tail, |
396 | pm); | 404 | pm); |
405 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
406 | gettext_noop ("# bytes currently in TCP buffers"), | ||
407 | -pm->message_size, | ||
408 | GNUNET_NO); | ||
397 | if (pm->transmit_cont != NULL) | 409 | if (pm->transmit_cont != NULL) |
398 | pm->transmit_cont (pm->transmit_cont_cls, | 410 | pm->transmit_cont (pm->transmit_cont_cls, |
399 | &session->target, GNUNET_OK); | 411 | &session->target, GNUNET_OK); |
@@ -490,6 +502,14 @@ disconnect_session (struct Session *session) | |||
490 | "Could not deliver message to `%4s', notifying.\n", | 502 | "Could not deliver message to `%4s', notifying.\n", |
491 | GNUNET_i2s (&session->target)); | 503 | GNUNET_i2s (&session->target)); |
492 | #endif | 504 | #endif |
505 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
506 | gettext_noop ("# bytes currently in TCP buffers"), | ||
507 | -pm->message_size, | ||
508 | GNUNET_NO); | ||
509 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
510 | gettext_noop ("# bytes discarded by TCP (disconnect)"), | ||
511 | pm->message_size, | ||
512 | GNUNET_NO); | ||
493 | GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, | 513 | GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, |
494 | session->pending_messages_tail, | 514 | session->pending_messages_tail, |
495 | pm); | 515 | pm); |
@@ -673,6 +693,10 @@ tcp_plugin_send (void *cls, | |||
673 | GNUNET_assert (session != NULL); | 693 | GNUNET_assert (session != NULL); |
674 | GNUNET_assert (session->client != NULL); | 694 | GNUNET_assert (session->client != NULL); |
675 | 695 | ||
696 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
697 | gettext_noop ("# bytes currently in TCP buffers"), | ||
698 | msgbuf_size, | ||
699 | GNUNET_NO); | ||
676 | /* create new message entry */ | 700 | /* create new message entry */ |
677 | pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size); | 701 | pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size); |
678 | pm->msg = (const char*) &pm[1]; | 702 | pm->msg = (const char*) &pm[1]; |