aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-03-16 14:11:54 +0000
committerChristian Grothoff <christian@grothoff.org>2010-03-16 14:11:54 +0000
commit1f5249e010b9d850e8aa6b6b745e55902051ac2e (patch)
tree463b1817b38103466413b759ef6c5269f6e8766c /src
parente854e44db02c14e84e5d03a65177138d2c206596 (diff)
downloadgnunet-1f5249e010b9d850e8aa6b6b745e55902051ac2e.tar.gz
gnunet-1f5249e010b9d850e8aa6b6b745e55902051ac2e.zip
stats
Diffstat (limited to 'src')
-rw-r--r--src/transport/gnunet-service-transport.c606
-rw-r--r--src/transport/plugin_transport_tcp.c24
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
1787static void send_periodic_ping(void *cls, 1824
1788 const struct GNUNET_SCHEDULER_TaskContext *tc); 1825/**
1826 * Closure for 'check_address_exists'.
1827 */
1828struct 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 */
1801static int 1863static int
1802check_pending_validation (void *cls, 1864check_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 */
1917static void 1890static void
1918handle_pong (void *cls, const struct GNUNET_MessageHeader *message, 1891timeout_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 */
2042struct 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 */
2077static int
2078check_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 */
2104static void 1993static void
2105timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 1994send_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 */
2138static int
2139rerun_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 */
2261static void 2124static int
2262send_periodic_ping (void *cls, 2125check_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 */
2240static void
2241handle_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];