diff options
author | Nathan S. Evans <evans@in.tum.de> | 2010-07-20 11:33:59 +0000 |
---|---|---|
committer | Nathan S. Evans <evans@in.tum.de> | 2010-07-20 11:33:59 +0000 |
commit | cf1d9e9e9f7765a9849f6f41f33ccb7615272eb5 (patch) | |
tree | 49f527798f9688dd9e64b82715ed2a415eb71888 /src/dht | |
parent | 0e35fa03c78b3e1f7c023ff554df7b315870b11c (diff) | |
download | gnunet-cf1d9e9e9f7765a9849f6f41f33ccb7615272eb5.tar.gz gnunet-cf1d9e9e9f7765a9849f6f41f33ccb7615272eb5.zip |
dht testcases and some minor other changes...
Diffstat (limited to 'src/dht')
-rw-r--r-- | src/dht/Makefile.am | 64 | ||||
-rw-r--r-- | src/dht/dht.h | 171 | ||||
-rw-r--r-- | src/dht/dht_api.c | 12 | ||||
-rw-r--r-- | src/dht/gnunet-dht-driver.c | 1243 | ||||
-rw-r--r-- | src/dht/gnunet-service-dht.c | 16 | ||||
-rw-r--r-- | src/dht/test_dht_api_data.conf | 4 | ||||
-rw-r--r-- | src/dht/test_dht_multipeer.c | 915 | ||||
-rw-r--r-- | src/dht/test_dht_multipeer_data.conf | 87 | ||||
-rw-r--r-- | src/dht/test_dht_twopeer_data.conf | 6 |
9 files changed, 2486 insertions, 32 deletions
diff --git a/src/dht/Makefile.am b/src/dht/Makefile.am index fbe0c8ab3..e3f78b870 100644 --- a/src/dht/Makefile.am +++ b/src/dht/Makefile.am | |||
@@ -1,16 +1,31 @@ | |||
1 | INCLUDES = -I$(top_srcdir)/src/include | 1 | INCLUDES = -I$(top_srcdir)/src/include |
2 | |||
3 | if MINGW | 2 | if MINGW |
4 | WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -lole32 -lshell32 -liconv -lstdc++ -lcomdlg32 -lgdi32 | 3 | WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -lole32 -lshell32 -liconv -lstdc++ -lcomdlg32 -lgdi32 |
5 | endif | 4 | endif |
6 | 5 | ||
6 | if HAVE_ZLIB | ||
7 | ZLIB_LNK = -lz | ||
8 | endif | ||
9 | |||
7 | if USE_COVERAGE | 10 | if USE_COVERAGE |
8 | AM_CFLAGS = --coverage -O0 | 11 | AM_CFLAGS = --coverage -O0 |
9 | XLIB = -lgcov | 12 | XLIB = -lgcov |
10 | endif | 13 | endif |
11 | 14 | ||
12 | lib_LTLIBRARIES = libgnunetdht.la | 15 | lib_LTLIBRARIES = libgnunetdht.la |
16 | # libgnunetdhtlog.la | ||
17 | |||
18 | #libgnunetdhtlog_la_SOURCES = \ | ||
19 | # dhtlog_mysql.c dhtlog.h | ||
20 | #libgnunetdhtlog_la_LIBADD = \ | ||
21 | # $(top_builddir)/src/util/libgnunetutil.la \ | ||
22 | # $(XLIB) | ||
23 | #libgnunetdhtlog_la_LDFLAGS = \ | ||
24 | # $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | ||
25 | # -lmysqlclient $(ZLIB_LNK) \ | ||
26 | # -version-info 0:0:0 | ||
13 | 27 | ||
28 | |||
14 | libgnunetdht_la_SOURCES = \ | 29 | libgnunetdht_la_SOURCES = \ |
15 | dht_api.c dht.h | 30 | dht_api.c dht.h |
16 | libgnunetdht_la_LIBADD = \ | 31 | libgnunetdht_la_LIBADD = \ |
@@ -20,12 +35,12 @@ libgnunetdht_la_LDFLAGS = \ | |||
20 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | 35 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ |
21 | -version-info 0:0:0 | 36 | -version-info 0:0:0 |
22 | 37 | ||
23 | |||
24 | bin_PROGRAMS = \ | 38 | bin_PROGRAMS = \ |
25 | gnunet-service-dht \ | 39 | gnunet-service-dht \ |
26 | gnunet-dht-get \ | 40 | gnunet-dht-get \ |
27 | gnunet-dht-get-peer \ | 41 | gnunet-dht-get-peer \ |
28 | gnunet-dht-put | 42 | gnunet-dht-put \ |
43 | gnunet-dht-driver | ||
29 | 44 | ||
30 | gnunet_service_dht_SOURCES = \ | 45 | gnunet_service_dht_SOURCES = \ |
31 | gnunet-service-dht.c | 46 | gnunet-service-dht.c |
@@ -37,6 +52,17 @@ gnunet_service_dht_LDADD = \ | |||
37 | $(top_builddir)/src/datacache/libgnunetdatacache.la \ | 52 | $(top_builddir)/src/datacache/libgnunetdatacache.la \ |
38 | $(top_builddir)/src/util/libgnunetutil.la | 53 | $(top_builddir)/src/util/libgnunetutil.la |
39 | 54 | ||
55 | #gnunet_service_dht_new_SOURCES = \ | ||
56 | # gnunet-service-dht-new.c | ||
57 | #gnunet_service_dht_new_LDADD = \ | ||
58 | # $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
59 | # $(top_builddir)/src/core/libgnunetcore.la \ | ||
60 | # $(top_builddir)/src/transport/libgnunettransport.la \ | ||
61 | # $(top_builddir)/src/hello/libgnunethello.la \ | ||
62 | # $(top_builddir)/src/datacache/libgnunetdatacache.la \ | ||
63 | # $(top_builddir)/src/util/libgnunetutil.la \ | ||
64 | # $(top_builddir)/src/dht/libgnunetdhtlog.la | ||
65 | |||
40 | gnunet_dht_get_SOURCES = \ | 66 | gnunet_dht_get_SOURCES = \ |
41 | gnunet-dht-get.c | 67 | gnunet-dht-get.c |
42 | gnunet_dht_get_LDADD = \ | 68 | gnunet_dht_get_LDADD = \ |
@@ -58,11 +84,23 @@ gnunet_dht_put_LDADD = \ | |||
58 | $(top_builddir)/src/dht/libgnunetdht.la \ | 84 | $(top_builddir)/src/dht/libgnunetdht.la \ |
59 | $(top_builddir)/src/core/libgnunetcore.la \ | 85 | $(top_builddir)/src/core/libgnunetcore.la \ |
60 | $(top_builddir)/src/util/libgnunetutil.la | 86 | $(top_builddir)/src/util/libgnunetutil.la |
87 | |||
88 | gnunet_dht_driver_SOURCES = \ | ||
89 | gnunet-dht-driver.c | ||
90 | gnunet_dht_driver_LDADD = \ | ||
91 | $(top_builddir)/src/dht/libgnunetdht.la \ | ||
92 | $(top_builddir)/src/dht/libgnunetdhtlog.la \ | ||
93 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
94 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
95 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
96 | $(top_builddir)/src/dht/libgnunetdhtlog.la | ||
61 | 97 | ||
62 | check_PROGRAMS = \ | 98 | check_PROGRAMS = \ |
63 | test_dht_api \ | 99 | test_dht_api \ |
64 | test_dht_twopeer \ | 100 | test_dht_twopeer \ |
65 | test_dht_twopeer_put_get | 101 | test_dht_twopeer_put_get \ |
102 | test_dht_multipeer | ||
103 | # test_dhtlog | ||
66 | 104 | ||
67 | TESTS = test_dht_api $(check_SCRIPTS) | 105 | TESTS = test_dht_api $(check_SCRIPTS) |
68 | 106 | ||
@@ -73,6 +111,13 @@ test_dht_api_LDADD = \ | |||
73 | $(top_builddir)/src/hello/libgnunethello.la \ | 111 | $(top_builddir)/src/hello/libgnunethello.la \ |
74 | $(top_builddir)/src/dht/libgnunetdht.la | 112 | $(top_builddir)/src/dht/libgnunetdht.la |
75 | 113 | ||
114 | test_dht_multipeer_SOURCES = \ | ||
115 | test_dht_multipeer.c | ||
116 | test_dht_multipeer_LDADD = \ | ||
117 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
118 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
119 | $(top_builddir)/src/dht/libgnunetdht.la | ||
120 | |||
76 | test_dht_twopeer_SOURCES = \ | 121 | test_dht_twopeer_SOURCES = \ |
77 | test_dht_twopeer.c | 122 | test_dht_twopeer.c |
78 | test_dht_twopeer_LDADD = \ | 123 | test_dht_twopeer_LDADD = \ |
@@ -87,11 +132,20 @@ test_dht_twopeer_put_get_LDADD = \ | |||
87 | $(top_builddir)/src/testing/libgnunettesting.la \ | 132 | $(top_builddir)/src/testing/libgnunettesting.la \ |
88 | $(top_builddir)/src/dht/libgnunetdht.la | 133 | $(top_builddir)/src/dht/libgnunetdht.la |
89 | 134 | ||
135 | #test_dhtlog_SOURCES = \ | ||
136 | # test_dhtlog.c | ||
137 | #test_dhtlog_LDADD = \ | ||
138 | # $(top_builddir)/src/util/libgnunetutil.la \ | ||
139 | # $(top_builddir)/src/testing/libgnunettesting.la \ | ||
140 | # $(top_builddir)/src/dht/libgnunetdht.la \ | ||
141 | # $(top_builddir)/src/dht/libgnunetdhtlog.la | ||
142 | |||
90 | EXTRA_DIST = \ | 143 | EXTRA_DIST = \ |
91 | $(check_SCRIPTS) \ | 144 | $(check_SCRIPTS) \ |
92 | test_dht_api_data.conf \ | 145 | test_dht_api_data.conf \ |
93 | test_dht_api_peer1.conf \ | 146 | test_dht_api_peer1.conf \ |
94 | test_dht_twopeer_data.conf | 147 | test_dht_twopeer_data.conf \ |
148 | test_dht_multipeer_data.conf | ||
95 | 149 | ||
96 | check_SCRIPTS = \ | 150 | check_SCRIPTS = \ |
97 | test_dht_tools.sh | 151 | test_dht_tools.sh |
diff --git a/src/dht/dht.h b/src/dht/dht.h index 319f6d26f..c6c9de1e1 100644 --- a/src/dht/dht.h +++ b/src/dht/dht.h | |||
@@ -29,9 +29,21 @@ | |||
29 | 29 | ||
30 | #define DEBUG_DHT GNUNET_NO | 30 | #define DEBUG_DHT GNUNET_NO |
31 | 31 | ||
32 | #define DEBUG_DHT_ROUTING GNUNET_YES | ||
33 | |||
34 | #define DHT_BLOOM_SIZE 16 | ||
35 | |||
36 | #define DHT_BLOOM_K 8 | ||
37 | |||
38 | #define MAX_OUTSTANDING_FORWARDS 100 | ||
39 | |||
40 | #define DHT_FORWARD_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5) | ||
41 | |||
42 | #define DHT_SEND_PRIORITY 4 | ||
43 | |||
32 | typedef void (*GNUNET_DHT_MessageReceivedHandler) (void *cls, | 44 | typedef void (*GNUNET_DHT_MessageReceivedHandler) (void *cls, |
33 | const struct GNUNET_MessageHeader | 45 | const struct GNUNET_MessageHeader |
34 | * msg); | 46 | *msg); |
35 | 47 | ||
36 | /** | 48 | /** |
37 | * Message which indicates the DHT should cancel outstanding | 49 | * Message which indicates the DHT should cancel outstanding |
@@ -54,17 +66,23 @@ struct GNUNET_DHT_StopMessage | |||
54 | */ | 66 | */ |
55 | uint64_t unique_id GNUNET_PACKED; | 67 | uint64_t unique_id GNUNET_PACKED; |
56 | 68 | ||
69 | /** | ||
70 | * Key of this request | ||
71 | */ | ||
72 | GNUNET_HashCode key; | ||
73 | |||
57 | }; | 74 | }; |
58 | 75 | ||
59 | 76 | ||
60 | /** | 77 | /** |
61 | * Generic DHT message, indicates that a route request | 78 | * Generic DHT message, indicates that a route request |
62 | * should be issued. | 79 | * should be issued, if coming from a client. Shared |
80 | * usage for api->server and P2P message passing. | ||
63 | */ | 81 | */ |
64 | struct GNUNET_DHT_RouteMessage | 82 | struct GNUNET_DHT_RouteMessage |
65 | { | 83 | { |
66 | /** | 84 | /** |
67 | * Type: GNUNET_MESSAGE_TYPE_DHT_ROUTE | 85 | * Type: GNUNET_MESSAGE_TYPE_LOCAL_DHT_ROUTE |
68 | */ | 86 | */ |
69 | struct GNUNET_MessageHeader header; | 87 | struct GNUNET_MessageHeader header; |
70 | 88 | ||
@@ -94,10 +112,13 @@ struct GNUNET_DHT_RouteMessage | |||
94 | 112 | ||
95 | }; | 113 | }; |
96 | 114 | ||
115 | /** | ||
116 | * Generic local route result message | ||
117 | */ | ||
97 | struct GNUNET_DHT_RouteResultMessage | 118 | struct GNUNET_DHT_RouteResultMessage |
98 | { | 119 | { |
99 | /** | 120 | /** |
100 | * Type: GNUNET_MESSAGE_TYPE_DHT_ROUTE_RESULT | 121 | * Type: GNUNET_MESSAGE_TYPE_LOCAL_DHT_ROUTE_RESULT |
101 | */ | 122 | */ |
102 | struct GNUNET_MessageHeader header; | 123 | struct GNUNET_MessageHeader header; |
103 | 124 | ||
@@ -107,25 +128,146 @@ struct GNUNET_DHT_RouteResultMessage | |||
107 | uint32_t options GNUNET_PACKED; | 128 | uint32_t options GNUNET_PACKED; |
108 | 129 | ||
109 | /** | 130 | /** |
131 | * Unique ID identifying this request (necessary for | ||
132 | * client to compare to sent requests) | ||
133 | */ | ||
134 | uint64_t unique_id GNUNET_PACKED; | ||
135 | |||
136 | /** | ||
110 | * The key that was searched for | 137 | * The key that was searched for |
111 | */ | 138 | */ |
112 | GNUNET_HashCode key; | 139 | GNUNET_HashCode key; |
113 | 140 | ||
141 | /* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */ | ||
142 | }; | ||
143 | |||
144 | /** | ||
145 | * Generic P2P DHT route message | ||
146 | */ | ||
147 | struct GNUNET_DHT_P2PRouteMessage | ||
148 | { | ||
149 | /** | ||
150 | * Type: GNUNET_MESSAGE_TYPE_P2P_DHT_ROUTE | ||
151 | */ | ||
152 | struct GNUNET_MessageHeader header; | ||
153 | |||
154 | /** | ||
155 | * Message options | ||
156 | */ | ||
157 | uint32_t options GNUNET_PACKED; | ||
158 | |||
159 | /** | ||
160 | * Hop count | ||
161 | */ | ||
162 | uint32_t hop_count GNUNET_PACKED; | ||
163 | |||
164 | /** | ||
165 | * Network size estimate | ||
166 | */ | ||
167 | uint32_t network_size GNUNET_PACKED; | ||
168 | |||
169 | /** | ||
170 | * Replication level for this message | ||
171 | */ | ||
172 | uint32_t desired_replication_level GNUNET_PACKED; | ||
173 | |||
114 | /** | 174 | /** |
115 | * Unique ID identifying this request | 175 | * Unique ID identifying this request |
116 | */ | 176 | */ |
117 | uint64_t unique_id GNUNET_PACKED; | 177 | uint64_t unique_id GNUNET_PACKED; |
118 | 178 | ||
179 | /* | ||
180 | * Bloomfilter to stop circular routes | ||
181 | */ | ||
182 | char bloomfilter[DHT_BLOOM_SIZE]; | ||
183 | |||
184 | /** | ||
185 | * FIXME: add DHT logging for analysis! | ||
186 | */ | ||
187 | #if LOG_SQL | ||
188 | /* | ||
189 | * Unique query id for sql database interaction. | ||
190 | */ | ||
191 | uint64_t queryuid; | ||
192 | |||
193 | /* | ||
194 | * Unique trial id for sql database interaction | ||
195 | */ | ||
196 | uint64_t trialuid; | ||
197 | |||
198 | #endif | ||
199 | |||
200 | /** | ||
201 | * The key to search for | ||
202 | */ | ||
203 | GNUNET_HashCode key; | ||
204 | |||
205 | /* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */ | ||
206 | |||
207 | }; | ||
208 | |||
209 | /** | ||
210 | * Generic P2P route result | ||
211 | * | ||
212 | * FIXME: One question is how much to include for a route result message. | ||
213 | * Assuming a peer receives such a message, but has no record of a | ||
214 | * route message, what should it do? It can either drop the message | ||
215 | * or try to forward it towards the original peer... However, for | ||
216 | * that to work we would need to include the original peer identity | ||
217 | * in the GET request, which adds even more data to the message. | ||
218 | */ | ||
219 | struct GNUNET_DHT_P2PRouteResultMessage | ||
220 | { | ||
221 | /** | ||
222 | * Type: GNUNET_MESSAGE_TYPE_P2P_DHT_ROUTE_RESULT | ||
223 | */ | ||
224 | struct GNUNET_MessageHeader header; | ||
225 | |||
226 | /** | ||
227 | * Message options | ||
228 | */ | ||
229 | uint32_t options GNUNET_PACKED; | ||
230 | |||
231 | /** | ||
232 | * Hop count | ||
233 | */ | ||
234 | uint32_t hop_count GNUNET_PACKED; | ||
235 | |||
236 | /** | ||
237 | * Unique ID identifying this request (may not be set) | ||
238 | */ | ||
239 | uint64_t unique_id GNUNET_PACKED; | ||
240 | |||
241 | /* | ||
242 | * Bloomfilter to stop circular routes | ||
243 | */ | ||
244 | char bloomfilter[DHT_BLOOM_SIZE]; | ||
245 | |||
246 | /** | ||
247 | * The key that was searched for | ||
248 | */ | ||
249 | GNUNET_HashCode key; | ||
250 | |||
251 | #if FORWARD_UNKNOWN | ||
252 | /** | ||
253 | * Network size estimate | ||
254 | */ | ||
255 | uint32_t network_size GNUNET_PACKED; | ||
256 | #endif | ||
257 | |||
119 | /* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */ | 258 | /* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */ |
120 | }; | 259 | }; |
121 | 260 | ||
261 | |||
122 | /** | 262 | /** |
123 | * Message to insert data into the DHT | 263 | * Message to insert data into the DHT, shared |
264 | * between api->server communication and P2P communication. | ||
265 | * The type must be different for the two purposes. | ||
124 | */ | 266 | */ |
125 | struct GNUNET_DHT_PutMessage | 267 | struct GNUNET_DHT_PutMessage |
126 | { | 268 | { |
127 | /** | 269 | /** |
128 | * Type: GNUNET_MESSAGE_TYPE_DHT_PUT | 270 | * Type: GNUNET_MESSAGE_TYPE_DHT_PUT / GNUNET_MESSAGE_TYPE_P2P_DHT_PUT |
129 | */ | 271 | */ |
130 | struct GNUNET_MessageHeader header; | 272 | struct GNUNET_MessageHeader header; |
131 | 273 | ||
@@ -148,12 +290,15 @@ struct GNUNET_DHT_PutMessage | |||
148 | 290 | ||
149 | 291 | ||
150 | /** | 292 | /** |
151 | * Message to request data from the DHT | 293 | * Message to request data from the DHT, shared |
294 | * between P2P requests and local get requests. | ||
295 | * Main difference is that if the request comes in | ||
296 | * locally we need to remember it (for client response). | ||
152 | */ | 297 | */ |
153 | struct GNUNET_DHT_GetMessage | 298 | struct GNUNET_DHT_GetMessage |
154 | { | 299 | { |
155 | /** | 300 | /** |
156 | * Type: GNUNET_MESSAGE_TYPE_DHT_GET | 301 | * Type: GNUNET_MESSAGE_TYPE_DHT_GET / GNUNET_MESSAGE_TYPE_P2P_DHT_GET |
157 | */ | 302 | */ |
158 | struct GNUNET_MessageHeader header; | 303 | struct GNUNET_MessageHeader header; |
159 | 304 | ||
@@ -165,12 +310,14 @@ struct GNUNET_DHT_GetMessage | |||
165 | }; | 310 | }; |
166 | 311 | ||
167 | /** | 312 | /** |
168 | * Message to return data from the DHT | 313 | * Message to return data either to the client API |
314 | * or to respond to a request received from another | ||
315 | * peer. Shared format, different types. | ||
169 | */ | 316 | */ |
170 | struct GNUNET_DHT_GetResultMessage | 317 | struct GNUNET_DHT_GetResultMessage |
171 | { | 318 | { |
172 | /** | 319 | /** |
173 | * Type: GNUNET_MESSAGE_TYPE_DHT_GET_RESULT | 320 | * Type: GNUNET_MESSAGE_TYPE_DHT_GET_RESULT / GNUNET_MESSAGE_TYPE_DHT_P2P_GET_RESULT |
174 | */ | 321 | */ |
175 | struct GNUNET_MessageHeader header; | 322 | struct GNUNET_MessageHeader header; |
176 | 323 | ||
@@ -180,9 +327,9 @@ struct GNUNET_DHT_GetResultMessage | |||
180 | uint32_t type; | 327 | uint32_t type; |
181 | 328 | ||
182 | /** | 329 | /** |
183 | * The key to search for | 330 | * The key that was searched for |
184 | */ | 331 | */ |
185 | GNUNET_HashCode key; | 332 | //GNUNET_HashCode key; |
186 | 333 | ||
187 | /** | 334 | /** |
188 | * When does this entry expire? | 335 | * When does this entry expire? |
diff --git a/src/dht/dht_api.c b/src/dht/dht_api.c index 6c65ac8f4..3ff4bc523 100644 --- a/src/dht/dht_api.c +++ b/src/dht/dht_api.c | |||
@@ -585,7 +585,7 @@ service_message_handler (void *cls, | |||
585 | 585 | ||
586 | switch (ntohs (msg->type)) | 586 | switch (ntohs (msg->type)) |
587 | { | 587 | { |
588 | case GNUNET_MESSAGE_TYPE_DHT_ROUTE_RESULT: | 588 | case GNUNET_MESSAGE_TYPE_LOCAL_DHT_ROUTE_RESULT: |
589 | { | 589 | { |
590 | dht_msg = (struct GNUNET_DHT_RouteResultMessage *) msg; | 590 | dht_msg = (struct GNUNET_DHT_RouteResultMessage *) msg; |
591 | uid = GNUNET_ntohll (dht_msg->unique_id); | 591 | uid = GNUNET_ntohll (dht_msg->unique_id); |
@@ -777,7 +777,7 @@ get_reply_iterator (void *cls, const struct GNUNET_MessageHeader *reply) | |||
777 | result_data = (char *) &result[1]; /* Set data pointer to end of message */ | 777 | result_data = (char *) &result[1]; /* Set data pointer to end of message */ |
778 | 778 | ||
779 | get_handle->get_context.iter (get_handle->get_context.iter_cls, | 779 | get_handle->get_context.iter (get_handle->get_context.iter_cls, |
780 | result->expiration, &result->key, | 780 | result->expiration, &get_handle->route_handle->key, |
781 | ntohs (result->type), data_size, result_data); | 781 | ntohs (result->type), data_size, result_data); |
782 | } | 782 | } |
783 | 783 | ||
@@ -868,9 +868,9 @@ GNUNET_DHT_route_start (struct GNUNET_DHT_Handle *handle, | |||
868 | route_handle->iter = iter; | 868 | route_handle->iter = iter; |
869 | route_handle->iter_cls = iter_cls; | 869 | route_handle->iter_cls = iter_cls; |
870 | route_handle->dht_handle = handle; | 870 | route_handle->dht_handle = handle; |
871 | route_handle->uid = handle->uid_gen++; | ||
871 | if (iter != NULL) | 872 | if (iter != NULL) |
872 | { | 873 | { |
873 | route_handle->uid = handle->uid_gen++; | ||
874 | hash_from_uid (route_handle->uid, &uid_key); | 874 | hash_from_uid (route_handle->uid, &uid_key); |
875 | GNUNET_CONTAINER_multihashmap_put (handle->outstanding_requests, | 875 | GNUNET_CONTAINER_multihashmap_put (handle->outstanding_requests, |
876 | &uid_key, route_handle, | 876 | &uid_key, route_handle, |
@@ -885,7 +885,7 @@ GNUNET_DHT_route_start (struct GNUNET_DHT_Handle *handle, | |||
885 | msize = sizeof (struct GNUNET_DHT_RouteMessage) + ntohs (enc->size); | 885 | msize = sizeof (struct GNUNET_DHT_RouteMessage) + ntohs (enc->size); |
886 | message = GNUNET_malloc (msize); | 886 | message = GNUNET_malloc (msize); |
887 | message->header.size = htons (msize); | 887 | message->header.size = htons (msize); |
888 | message->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_ROUTE); | 888 | message->header.type = htons (GNUNET_MESSAGE_TYPE_LOCAL_DHT_ROUTE); |
889 | memcpy (&message->key, key, sizeof (GNUNET_HashCode)); | 889 | memcpy (&message->key, key, sizeof (GNUNET_HashCode)); |
890 | message->options = htonl (options); | 890 | message->options = htonl (options); |
891 | message->desired_replication_level = htonl (options); | 891 | message->desired_replication_level = htonl (options); |
@@ -983,13 +983,14 @@ GNUNET_DHT_route_stop (struct GNUNET_DHT_RouteHandle *route_handle, | |||
983 | msize = sizeof (struct GNUNET_DHT_StopMessage); | 983 | msize = sizeof (struct GNUNET_DHT_StopMessage); |
984 | message = GNUNET_malloc (msize); | 984 | message = GNUNET_malloc (msize); |
985 | message->header.size = htons (msize); | 985 | message->header.size = htons (msize); |
986 | message->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_STOP); | 986 | message->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_ROUTE_STOP); |
987 | #if DEBUG_DHT_API | 987 | #if DEBUG_DHT_API |
988 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 988 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
989 | "`%s': Remove outstanding request for uid %llu\n", "DHT API", | 989 | "`%s': Remove outstanding request for uid %llu\n", "DHT API", |
990 | route_handle->uid); | 990 | route_handle->uid); |
991 | #endif | 991 | #endif |
992 | message->unique_id = GNUNET_htonll (route_handle->uid); | 992 | message->unique_id = GNUNET_htonll (route_handle->uid); |
993 | memcpy(&message->key, &route_handle->key, sizeof(GNUNET_HashCode)); | ||
993 | pending = GNUNET_malloc (sizeof (struct PendingMessage)); | 994 | pending = GNUNET_malloc (sizeof (struct PendingMessage)); |
994 | pending->msg = (struct GNUNET_MessageHeader *) message; | 995 | pending->msg = (struct GNUNET_MessageHeader *) message; |
995 | pending->timeout = GNUNET_TIME_relative_get_forever(); | 996 | pending->timeout = GNUNET_TIME_relative_get_forever(); |
@@ -1009,6 +1010,7 @@ GNUNET_DHT_route_stop (struct GNUNET_DHT_RouteHandle *route_handle, | |||
1009 | } | 1010 | } |
1010 | else | 1011 | else |
1011 | { | 1012 | { |
1013 | GNUNET_free(pending); | ||
1012 | GNUNET_break(0); | 1014 | GNUNET_break(0); |
1013 | } | 1015 | } |
1014 | 1016 | ||
diff --git a/src/dht/gnunet-dht-driver.c b/src/dht/gnunet-dht-driver.c new file mode 100644 index 000000000..2081df970 --- /dev/null +++ b/src/dht/gnunet-dht-driver.c | |||
@@ -0,0 +1,1243 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file dht/gnunet-dht-driver.c | ||
22 | * @brief Driver for setting up a group of gnunet peers and | ||
23 | * then issuing GETS and PUTS on the DHT. Coarse results | ||
24 | * are reported, fine grained results (if requested) are | ||
25 | * logged to a (mysql) database. | ||
26 | * | ||
27 | * TODO: Add multiple database support; alternatively, dump | ||
28 | * sql readable (or easily transformed) logs to disk | ||
29 | * for reassembly later. This could remove the mysql | ||
30 | * server as a bottleneck during testing. | ||
31 | */ | ||
32 | #include "platform.h" | ||
33 | #include "gnunet_testing_lib.h" | ||
34 | #include "gnunet_core_service.h" | ||
35 | #include "gnunet_dht_service.h" | ||
36 | #include "dhtlog.h" | ||
37 | |||
38 | /* DEFINES */ | ||
39 | #define VERBOSE GNUNET_YES | ||
40 | |||
41 | /* Timeout for entire driver to run */ | ||
42 | #define DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5) | ||
43 | |||
44 | /* Timeout for waiting for (individual) replies to get requests */ | ||
45 | #define DEFAULT_GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90) | ||
46 | |||
47 | /* Timeout for waiting for gets to be sent to the service */ | ||
48 | #define DEFAULT_GET_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10) | ||
49 | |||
50 | /* Timeout for waiting for puts to be sent to the service */ | ||
51 | #define DEFAULT_PUT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10) | ||
52 | |||
53 | #define DEFAULT_SECONDS_PER_PEER_START GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 45) | ||
54 | |||
55 | #define DEFAULT_TEST_DATA_SIZE 8 | ||
56 | |||
57 | #define DEFAULT_MAX_OUTSTANDING_PUTS 10 | ||
58 | |||
59 | #define DEFAULT_MAX_OUTSTANDING_GETS 10 | ||
60 | |||
61 | #define DEFAULT_CONNECT_TIMEOUT 60 | ||
62 | |||
63 | #define DEFAULT_TOPOLOGY_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 8) | ||
64 | |||
65 | /* Structs */ | ||
66 | |||
67 | struct TestPutContext | ||
68 | { | ||
69 | /* This is a linked list */ | ||
70 | struct TestPutContext *next; | ||
71 | |||
72 | /** | ||
73 | * Handle to the first peers DHT service (via the API) | ||
74 | */ | ||
75 | struct GNUNET_DHT_Handle *dht_handle; | ||
76 | |||
77 | /** | ||
78 | * Handle to the PUT peer daemon | ||
79 | */ | ||
80 | struct GNUNET_TESTING_Daemon *daemon; | ||
81 | |||
82 | /** | ||
83 | * Identifier for this PUT | ||
84 | */ | ||
85 | uint32_t uid; | ||
86 | |||
87 | /** | ||
88 | * Task for disconnecting DHT handles | ||
89 | */ | ||
90 | GNUNET_SCHEDULER_TaskIdentifier disconnect_task; | ||
91 | }; | ||
92 | |||
93 | struct TestGetContext | ||
94 | { | ||
95 | /* This is a linked list */ | ||
96 | struct TestGetContext *next; | ||
97 | |||
98 | /** | ||
99 | * Handle to the first peers DHT service (via the API) | ||
100 | */ | ||
101 | struct GNUNET_DHT_Handle *dht_handle; | ||
102 | |||
103 | /** | ||
104 | * Handle for the DHT get request | ||
105 | */ | ||
106 | struct GNUNET_DHT_GetHandle *get_handle; | ||
107 | |||
108 | /** | ||
109 | * Handle to the GET peer daemon | ||
110 | */ | ||
111 | struct GNUNET_TESTING_Daemon *daemon; | ||
112 | |||
113 | /** | ||
114 | * Identifier for this GET | ||
115 | */ | ||
116 | uint32_t uid; | ||
117 | |||
118 | /** | ||
119 | * Task for disconnecting DHT handles (and stopping GET) | ||
120 | */ | ||
121 | GNUNET_SCHEDULER_TaskIdentifier disconnect_task; | ||
122 | |||
123 | /** | ||
124 | * Whether or not this request has been fulfilled already. | ||
125 | */ | ||
126 | int succeeded; | ||
127 | }; | ||
128 | |||
129 | /** | ||
130 | * Simple struct to keep track of progress, and print a | ||
131 | * nice little percentage meter for long running tasks. | ||
132 | */ | ||
133 | struct ProgressMeter | ||
134 | { | ||
135 | unsigned int total; | ||
136 | |||
137 | unsigned int modnum; | ||
138 | |||
139 | unsigned int dotnum; | ||
140 | |||
141 | unsigned int completed; | ||
142 | |||
143 | int print; | ||
144 | |||
145 | char *startup_string; | ||
146 | }; | ||
147 | |||
148 | /* Globals */ | ||
149 | |||
150 | /** | ||
151 | * Timeout to let all get requests happen. | ||
152 | */ | ||
153 | static struct GNUNET_TIME_Relative all_get_timeout; | ||
154 | |||
155 | /** | ||
156 | * Per get timeout | ||
157 | */ | ||
158 | static struct GNUNET_TIME_Relative get_timeout; | ||
159 | |||
160 | static struct GNUNET_TIME_Relative get_delay; | ||
161 | |||
162 | static struct GNUNET_TIME_Relative put_delay; | ||
163 | |||
164 | static struct GNUNET_TIME_Relative seconds_per_peer_start; | ||
165 | |||
166 | static unsigned long long test_data_size = DEFAULT_TEST_DATA_SIZE; | ||
167 | |||
168 | static unsigned long long max_outstanding_puts = DEFAULT_MAX_OUTSTANDING_PUTS; | ||
169 | |||
170 | static unsigned long long max_outstanding_gets = DEFAULT_MAX_OUTSTANDING_GETS; | ||
171 | |||
172 | static unsigned long long malicious_getters; | ||
173 | |||
174 | static unsigned long long malicious_putters; | ||
175 | |||
176 | static unsigned long long malicious_droppers; | ||
177 | |||
178 | static unsigned long long settle_time; | ||
179 | |||
180 | static struct GNUNET_DHTLOG_Handle *dhtlog_handle; | ||
181 | |||
182 | static unsigned long long trialuid; | ||
183 | |||
184 | /** | ||
185 | * List of GETS to perform | ||
186 | */ | ||
187 | struct TestGetContext *all_gets; | ||
188 | |||
189 | /** | ||
190 | * List of PUTS to perform | ||
191 | */ | ||
192 | struct TestPutContext *all_puts; | ||
193 | |||
194 | /** | ||
195 | * Directory to store temporary data in, defined in config file | ||
196 | */ | ||
197 | static char *test_directory; | ||
198 | |||
199 | /** | ||
200 | * Variable used to store the number of connections we should wait for. | ||
201 | */ | ||
202 | static unsigned int expected_connections; | ||
203 | |||
204 | /** | ||
205 | * Variable used to keep track of how many peers aren't yet started. | ||
206 | */ | ||
207 | static unsigned long long peers_left; | ||
208 | |||
209 | /** | ||
210 | * Handle to the set of all peers run for this test. | ||
211 | */ | ||
212 | static struct GNUNET_TESTING_PeerGroup *pg; | ||
213 | |||
214 | /** | ||
215 | * Global scheduler, used for all GNUNET_SCHEDULER_* functions. | ||
216 | */ | ||
217 | static struct GNUNET_SCHEDULER_Handle *sched; | ||
218 | |||
219 | /** | ||
220 | * Total number of peers to run, set based on config file. | ||
221 | */ | ||
222 | static unsigned long long num_peers; | ||
223 | |||
224 | /** | ||
225 | * Total number of items to insert. | ||
226 | */ | ||
227 | static unsigned long long num_puts; | ||
228 | |||
229 | /** | ||
230 | * Total number of items to attempt to get. | ||
231 | */ | ||
232 | static unsigned long long num_gets; | ||
233 | |||
234 | /** | ||
235 | * How many puts do we currently have in flight? | ||
236 | */ | ||
237 | static unsigned long long outstanding_puts; | ||
238 | |||
239 | /** | ||
240 | * How many puts are done? | ||
241 | */ | ||
242 | static unsigned long long puts_completed; | ||
243 | |||
244 | /** | ||
245 | * How many puts do we currently have in flight? | ||
246 | */ | ||
247 | static unsigned long long outstanding_gets; | ||
248 | |||
249 | /** | ||
250 | * How many gets are done? | ||
251 | */ | ||
252 | static unsigned long long gets_completed; | ||
253 | |||
254 | /** | ||
255 | * How many gets failed? | ||
256 | */ | ||
257 | static unsigned long long gets_failed; | ||
258 | |||
259 | /** | ||
260 | * Global used to count how many connections we have currently | ||
261 | * been notified about (how many times has topology_callback been called | ||
262 | * with success?) | ||
263 | */ | ||
264 | static unsigned int total_connections; | ||
265 | |||
266 | /** | ||
267 | * Global used to count how many failed connections we have | ||
268 | * been notified about (how many times has topology_callback | ||
269 | * been called with failure?) | ||
270 | */ | ||
271 | static unsigned int failed_connections; | ||
272 | |||
273 | /* Task handle to use to schedule shutdown if something goes wrong */ | ||
274 | GNUNET_SCHEDULER_TaskIdentifier die_task; | ||
275 | |||
276 | static char *blacklist_transports; | ||
277 | |||
278 | static enum GNUNET_TESTING_Topology topology; | ||
279 | |||
280 | static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */ | ||
281 | |||
282 | static enum GNUNET_TESTING_Topology connect_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ | ||
283 | |||
284 | static enum GNUNET_TESTING_TopologyOption connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; | ||
285 | |||
286 | static double connect_topology_option_modifier = 0.0; | ||
287 | |||
288 | static struct ProgressMeter *hostkey_meter; | ||
289 | |||
290 | static struct ProgressMeter *peer_start_meter; | ||
291 | |||
292 | static struct ProgressMeter *peer_connect_meter; | ||
293 | |||
294 | static struct ProgressMeter *put_meter; | ||
295 | |||
296 | static struct ProgressMeter *get_meter; | ||
297 | |||
298 | /* Global return value (0 for success, anything else for failure) */ | ||
299 | static int ok; | ||
300 | |||
301 | /** | ||
302 | * Create a meter to keep track of the progress of some task. | ||
303 | * | ||
304 | * @param total the total number of items to complete | ||
305 | * @param start_string a string to prefix the meter with (if printing) | ||
306 | * @param print GNUNET_YES to print the meter, GNUNET_NO to count | ||
307 | * internally only | ||
308 | * | ||
309 | * @return the progress meter | ||
310 | */ | ||
311 | static struct ProgressMeter * | ||
312 | create_meter(unsigned int total, char * start_string, int print) | ||
313 | { | ||
314 | struct ProgressMeter *ret; | ||
315 | ret = GNUNET_malloc(sizeof(struct ProgressMeter)); | ||
316 | ret->print = print; | ||
317 | ret->total = total; | ||
318 | ret->modnum = total / 4; | ||
319 | ret->dotnum = (total / 50) + 1; | ||
320 | if (start_string != NULL) | ||
321 | ret->startup_string = GNUNET_strdup(start_string); | ||
322 | else | ||
323 | ret->startup_string = GNUNET_strdup(""); | ||
324 | |||
325 | return ret; | ||
326 | } | ||
327 | |||
328 | /** | ||
329 | * Update progress meter (increment by one). | ||
330 | * | ||
331 | * @param meter the meter to update and print info for | ||
332 | * | ||
333 | * @return GNUNET_YES if called the total requested, | ||
334 | * GNUNET_NO if more items expected | ||
335 | */ | ||
336 | static int | ||
337 | update_meter(struct ProgressMeter *meter) | ||
338 | { | ||
339 | if (meter->print == GNUNET_YES) | ||
340 | { | ||
341 | if (meter->completed % meter->modnum == 0) | ||
342 | { | ||
343 | if (meter->completed == 0) | ||
344 | { | ||
345 | fprintf(stdout, "%sProgress: [0%%", meter->startup_string); | ||
346 | } | ||
347 | else | ||
348 | fprintf(stdout, "%d%%", (int)(((float)meter->completed / meter->total) * 100)); | ||
349 | } | ||
350 | else if (meter->completed % meter->dotnum == 0) | ||
351 | fprintf(stdout, "."); | ||
352 | |||
353 | if (meter->completed + 1 == meter->total) | ||
354 | fprintf(stdout, "%d%%]\n", 100); | ||
355 | fflush(stdout); | ||
356 | } | ||
357 | meter->completed++; | ||
358 | |||
359 | if (meter->completed == meter->total) | ||
360 | return GNUNET_YES; | ||
361 | return GNUNET_NO; | ||
362 | } | ||
363 | |||
364 | /** | ||
365 | * Release resources for meter | ||
366 | * | ||
367 | * @param meter the meter to free | ||
368 | */ | ||
369 | static void | ||
370 | free_meter(struct ProgressMeter *meter) | ||
371 | { | ||
372 | GNUNET_free_non_null(meter->startup_string); | ||
373 | GNUNET_free_non_null(meter); | ||
374 | } | ||
375 | |||
376 | /** | ||
377 | * Check whether peers successfully shut down. | ||
378 | */ | ||
379 | void shutdown_callback (void *cls, | ||
380 | const char *emsg) | ||
381 | { | ||
382 | if (emsg != NULL) | ||
383 | { | ||
384 | if (ok == 0) | ||
385 | ok = 2; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | /** | ||
390 | * Task to release DHT handles for PUT | ||
391 | */ | ||
392 | static void | ||
393 | put_disconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
394 | { | ||
395 | struct TestPutContext *test_put = cls; | ||
396 | test_put->disconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
397 | GNUNET_DHT_disconnect(test_put->dht_handle); | ||
398 | test_put->dht_handle = NULL; | ||
399 | } | ||
400 | |||
401 | /** | ||
402 | * Function scheduled to be run on the successful completion of this | ||
403 | * testcase. | ||
404 | */ | ||
405 | static void | ||
406 | finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
407 | { | ||
408 | GNUNET_assert (pg != NULL); | ||
409 | struct TestPutContext *test_put = all_puts; | ||
410 | struct TestGetContext *test_get = all_gets; | ||
411 | |||
412 | while (test_put != NULL) | ||
413 | { | ||
414 | if (test_put->disconnect_task != GNUNET_SCHEDULER_NO_TASK) | ||
415 | GNUNET_SCHEDULER_cancel(sched, test_put->disconnect_task); | ||
416 | if (test_put->dht_handle != NULL) | ||
417 | GNUNET_DHT_disconnect(test_put->dht_handle); | ||
418 | test_put = test_put->next; | ||
419 | } | ||
420 | |||
421 | while (test_get != NULL) | ||
422 | { | ||
423 | if (test_get->disconnect_task != GNUNET_SCHEDULER_NO_TASK) | ||
424 | GNUNET_SCHEDULER_cancel(sched, test_get->disconnect_task); | ||
425 | if (test_get->get_handle != NULL) | ||
426 | GNUNET_DHT_get_stop(test_get->get_handle, NULL, NULL); | ||
427 | if (test_get->dht_handle != NULL) | ||
428 | GNUNET_DHT_disconnect(test_get->dht_handle); | ||
429 | test_get = test_get->next; | ||
430 | } | ||
431 | |||
432 | GNUNET_TESTING_daemons_stop (pg, DEFAULT_TIMEOUT, &shutdown_callback, NULL); | ||
433 | |||
434 | /* FIXME: optionally get stats for dropped messages, etc. */ | ||
435 | if (dhtlog_handle != NULL) | ||
436 | dhtlog_handle->update_trial (trialuid, 0, 0, 0); | ||
437 | |||
438 | if (hostkey_meter != NULL) | ||
439 | free_meter(hostkey_meter); | ||
440 | if (hostkey_meter != NULL) | ||
441 | free_meter(peer_start_meter); | ||
442 | if (hostkey_meter != NULL) | ||
443 | free_meter(peer_connect_meter); | ||
444 | if (hostkey_meter != NULL) | ||
445 | free_meter(put_meter); | ||
446 | if (hostkey_meter != NULL) | ||
447 | free_meter(get_meter); | ||
448 | |||
449 | ok = 0; | ||
450 | } | ||
451 | |||
452 | |||
453 | /** | ||
454 | * Check if the get_handle is being used, if so stop the request. Either | ||
455 | * way, schedule the end_badly_cont function which actually shuts down the | ||
456 | * test. | ||
457 | */ | ||
458 | static void | ||
459 | end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
460 | { | ||
461 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failing test with error: `%s'!\n", (char *)cls); | ||
462 | |||
463 | struct TestPutContext *test_put = all_puts; | ||
464 | struct TestGetContext *test_get = all_gets; | ||
465 | |||
466 | while (test_put != NULL) | ||
467 | { | ||
468 | if (test_put->disconnect_task != GNUNET_SCHEDULER_NO_TASK) | ||
469 | GNUNET_SCHEDULER_cancel(sched, test_put->disconnect_task); | ||
470 | if (test_put->dht_handle != NULL) | ||
471 | GNUNET_DHT_disconnect(test_put->dht_handle); | ||
472 | test_put = test_put->next; | ||
473 | } | ||
474 | |||
475 | while (test_get != NULL) | ||
476 | { | ||
477 | if (test_get->disconnect_task != GNUNET_SCHEDULER_NO_TASK) | ||
478 | GNUNET_SCHEDULER_cancel(sched, test_get->disconnect_task); | ||
479 | if (test_get->get_handle != NULL) | ||
480 | GNUNET_DHT_get_stop(test_get->get_handle, NULL, NULL); | ||
481 | if (test_get->dht_handle != NULL) | ||
482 | GNUNET_DHT_disconnect(test_get->dht_handle); | ||
483 | test_get = test_get->next; | ||
484 | } | ||
485 | |||
486 | GNUNET_TESTING_daemons_stop (pg, DEFAULT_TIMEOUT, &shutdown_callback, NULL); | ||
487 | |||
488 | if (hostkey_meter != NULL) | ||
489 | free_meter(hostkey_meter); | ||
490 | if (hostkey_meter != NULL) | ||
491 | free_meter(peer_start_meter); | ||
492 | if (hostkey_meter != NULL) | ||
493 | free_meter(peer_connect_meter); | ||
494 | if (hostkey_meter != NULL) | ||
495 | free_meter(put_meter); | ||
496 | if (hostkey_meter != NULL) | ||
497 | free_meter(get_meter); | ||
498 | |||
499 | ok = 1; | ||
500 | } | ||
501 | |||
502 | /** | ||
503 | * Task to release DHT handle associated with GET request. | ||
504 | */ | ||
505 | static void | ||
506 | get_stop_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
507 | { | ||
508 | struct TestGetContext *test_get = cls; | ||
509 | outstanding_gets--; /* GET is really finished */ | ||
510 | GNUNET_DHT_disconnect(test_get->dht_handle); | ||
511 | test_get->dht_handle = NULL; | ||
512 | |||
513 | #if VERBOSE > 1 | ||
514 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%d gets succeeded, %d gets failed!\n", gets_completed, gets_failed); | ||
515 | #endif | ||
516 | update_meter(get_meter); | ||
517 | if ((gets_completed == num_gets) && (outstanding_gets == 0))/* All gets successful */ | ||
518 | { | ||
519 | GNUNET_SCHEDULER_cancel(sched, die_task); | ||
520 | GNUNET_SCHEDULER_add_now(sched, &finish_testing, NULL); | ||
521 | } | ||
522 | else if ((gets_completed + gets_failed == num_gets) && (outstanding_gets == 0)) /* Had some failures */ | ||
523 | { | ||
524 | GNUNET_SCHEDULER_cancel(sched, die_task); | ||
525 | GNUNET_SCHEDULER_add_now(sched, &finish_testing, NULL); | ||
526 | } | ||
527 | } | ||
528 | |||
529 | /** | ||
530 | * Task to release get handle. | ||
531 | */ | ||
532 | static void | ||
533 | get_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
534 | { | ||
535 | struct TestGetContext *test_get = cls; | ||
536 | |||
537 | if (tc->reason == GNUNET_SCHEDULER_REASON_TIMEOUT) | ||
538 | gets_failed++; | ||
539 | GNUNET_assert(test_get->get_handle != NULL); | ||
540 | GNUNET_DHT_get_stop(test_get->get_handle, &get_stop_finished, test_get); | ||
541 | test_get->get_handle = NULL; | ||
542 | test_get->disconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
543 | } | ||
544 | |||
545 | /** | ||
546 | * Iterator called if the GET request initiated returns a response. | ||
547 | * | ||
548 | * @param cls closure | ||
549 | * @param exp when will this value expire | ||
550 | * @param key key of the result | ||
551 | * @param type type of the result | ||
552 | * @param size number of bytes in data | ||
553 | * @param data pointer to the result data | ||
554 | */ | ||
555 | void get_result_iterator (void *cls, | ||
556 | struct GNUNET_TIME_Absolute exp, | ||
557 | const GNUNET_HashCode * key, | ||
558 | uint32_t type, | ||
559 | uint32_t size, | ||
560 | const void *data) | ||
561 | { | ||
562 | struct TestGetContext *test_get = cls; | ||
563 | GNUNET_HashCode search_key; /* Key stored under */ | ||
564 | char original_data[test_data_size]; /* Made up data to store */ | ||
565 | |||
566 | memset(original_data, test_get->uid, sizeof(original_data)); | ||
567 | GNUNET_CRYPTO_hash(original_data, test_data_size, &search_key); | ||
568 | |||
569 | if (test_get->succeeded == GNUNET_YES) | ||
570 | return; /* Get has already been successful, probably ending now */ | ||
571 | |||
572 | if ((0 != memcmp(&search_key, key, sizeof (GNUNET_HashCode))) || (0 != memcmp(original_data, data, sizeof(original_data)))) | ||
573 | { | ||
574 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Key or data is not the same as was inserted!\n"); | ||
575 | } | ||
576 | else | ||
577 | { | ||
578 | gets_completed++; | ||
579 | test_get->succeeded = GNUNET_YES; | ||
580 | } | ||
581 | #if VERBOSE > 1 | ||
582 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct GET response!\n"); | ||
583 | #endif | ||
584 | GNUNET_SCHEDULER_cancel(sched, test_get->disconnect_task); | ||
585 | GNUNET_SCHEDULER_add_continuation(sched, &get_stop_task, test_get, GNUNET_SCHEDULER_REASON_PREREQ_DONE); | ||
586 | } | ||
587 | |||
588 | /** | ||
589 | * Continuation telling us GET request was sent. | ||
590 | */ | ||
591 | static void | ||
592 | get_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
593 | { | ||
594 | // Is there something to be done here? | ||
595 | if (tc->reason != GNUNET_SCHEDULER_REASON_PREREQ_DONE) | ||
596 | return; | ||
597 | } | ||
598 | |||
599 | /** | ||
600 | * Set up some data, and call API PUT function | ||
601 | */ | ||
602 | static void | ||
603 | do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
604 | { | ||
605 | struct TestGetContext *test_get = cls; | ||
606 | GNUNET_HashCode key; /* Made up key to store data under */ | ||
607 | char data[test_data_size]; /* Made up data to store */ | ||
608 | |||
609 | if (num_gets == 0) | ||
610 | { | ||
611 | GNUNET_SCHEDULER_cancel(sched, die_task); | ||
612 | GNUNET_SCHEDULER_add_now(sched, &finish_testing, NULL); | ||
613 | } | ||
614 | if (test_get == NULL) | ||
615 | return; /* End of the list */ | ||
616 | memset(data, test_get->uid, sizeof(data)); | ||
617 | GNUNET_CRYPTO_hash(data, test_data_size, &key); | ||
618 | |||
619 | if (outstanding_gets > max_outstanding_gets) | ||
620 | { | ||
621 | GNUNET_SCHEDULER_add_delayed (sched, get_delay, &do_get, test_get); | ||
622 | return; | ||
623 | } | ||
624 | |||
625 | test_get->dht_handle = GNUNET_DHT_connect(sched, test_get->daemon->cfg, 10); | ||
626 | /* Insert the data at the first peer */ | ||
627 | GNUNET_assert(test_get->dht_handle != NULL); | ||
628 | outstanding_gets++; | ||
629 | test_get->get_handle = GNUNET_DHT_get_start(test_get->dht_handle, | ||
630 | GNUNET_TIME_relative_get_forever(), | ||
631 | 1, | ||
632 | &key, | ||
633 | &get_result_iterator, | ||
634 | test_get, | ||
635 | &get_continuation, | ||
636 | test_get); | ||
637 | #if VERBOSE > 1 | ||
638 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting get for uid %u from peer %s\n", | ||
639 | test_get->uid, | ||
640 | test_get->daemon->shortname); | ||
641 | #endif | ||
642 | test_get->disconnect_task = GNUNET_SCHEDULER_add_delayed(sched, get_timeout, &get_stop_task, test_get); | ||
643 | GNUNET_SCHEDULER_add_now (sched, &do_get, test_get->next); | ||
644 | } | ||
645 | |||
646 | /** | ||
647 | * Called when the PUT request has been transmitted to the DHT service. | ||
648 | * Schedule the GET request for some time in the future. | ||
649 | */ | ||
650 | static void | ||
651 | put_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
652 | { | ||
653 | struct TestPutContext *test_put = cls; | ||
654 | outstanding_puts--; | ||
655 | puts_completed++; | ||
656 | |||
657 | GNUNET_SCHEDULER_cancel(sched, test_put->disconnect_task); | ||
658 | test_put->disconnect_task = GNUNET_SCHEDULER_add_now(sched, &put_disconnect_task, test_put); | ||
659 | if (GNUNET_YES == update_meter(put_meter)) | ||
660 | { | ||
661 | GNUNET_assert(outstanding_puts == 0); | ||
662 | GNUNET_SCHEDULER_cancel (sched, die_task); | ||
663 | die_task = GNUNET_SCHEDULER_add_delayed (sched, all_get_timeout, | ||
664 | &end_badly, "from do gets"); | ||
665 | GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 100), &do_get, all_gets); | ||
666 | return; | ||
667 | } | ||
668 | } | ||
669 | |||
670 | /** | ||
671 | * Set up some data, and call API PUT function | ||
672 | */ | ||
673 | static void | ||
674 | do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
675 | { | ||
676 | struct TestPutContext *test_put = cls; | ||
677 | GNUNET_HashCode key; /* Made up key to store data under */ | ||
678 | char data[test_data_size]; /* Made up data to store */ | ||
679 | uint32_t rand; | ||
680 | |||
681 | if (test_put == NULL) | ||
682 | return; /* End of list */ | ||
683 | |||
684 | memset(data, test_put->uid, sizeof(data)); | ||
685 | GNUNET_CRYPTO_hash(data, test_data_size, &key); | ||
686 | |||
687 | if (outstanding_puts > max_outstanding_puts) | ||
688 | { | ||
689 | GNUNET_SCHEDULER_add_delayed (sched, put_delay, &do_put, test_put); | ||
690 | return; | ||
691 | } | ||
692 | |||
693 | #if VERBOSE > 1 | ||
694 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting put for uid %u from peer %s\n", | ||
695 | test_put->uid, | ||
696 | test_put->daemon->shortname); | ||
697 | #endif | ||
698 | test_put->dht_handle = GNUNET_DHT_connect(sched, test_put->daemon->cfg, 10); | ||
699 | |||
700 | GNUNET_assert(test_put->dht_handle != NULL); | ||
701 | outstanding_puts++; | ||
702 | GNUNET_DHT_put(test_put->dht_handle, | ||
703 | &key, | ||
704 | 1, | ||
705 | sizeof(data), data, | ||
706 | GNUNET_TIME_absolute_get_forever(), | ||
707 | GNUNET_TIME_relative_get_forever(), | ||
708 | &put_finished, test_put); | ||
709 | test_put->disconnect_task = GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_get_forever(), &put_disconnect_task, test_put); | ||
710 | rand = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, 2); | ||
711 | GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, rand), &do_put, test_put->next); | ||
712 | } | ||
713 | |||
714 | |||
715 | /** | ||
716 | * Set up some all of the put and get operations we want | ||
717 | * to do. Allocate data structure for each, add to list, | ||
718 | * then call actual insert functions. | ||
719 | */ | ||
720 | static void | ||
721 | setup_puts_and_gets (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
722 | { | ||
723 | int i; | ||
724 | uint32_t temp_daemon; | ||
725 | struct TestPutContext *test_put; | ||
726 | struct TestGetContext *test_get; | ||
727 | int remember[num_puts][num_peers]; | ||
728 | |||
729 | for (i = 0; i < num_puts; i++) | ||
730 | { | ||
731 | test_put = GNUNET_malloc(sizeof(struct TestPutContext)); | ||
732 | test_put->uid = i; | ||
733 | temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers); | ||
734 | test_put->daemon = GNUNET_TESTING_daemon_get(pg, temp_daemon); | ||
735 | test_put->next = all_puts; | ||
736 | all_puts = test_put; | ||
737 | } | ||
738 | |||
739 | for (i = 0; i < num_gets; i++) | ||
740 | { | ||
741 | test_get = GNUNET_malloc(sizeof(struct TestGetContext)); | ||
742 | test_get->uid = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_puts); | ||
743 | temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers); | ||
744 | while (remember[test_get->uid][temp_daemon] == 1) | ||
745 | temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers); | ||
746 | test_get->daemon = GNUNET_TESTING_daemon_get(pg, temp_daemon); | ||
747 | remember[test_get->uid][temp_daemon] = 1; | ||
748 | test_get->next = all_gets; | ||
749 | all_gets = test_get; | ||
750 | } | ||
751 | |||
752 | GNUNET_SCHEDULER_cancel (sched, die_task); | ||
753 | die_task = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, num_puts * 2), | ||
754 | &end_badly, "from do puts"); | ||
755 | GNUNET_SCHEDULER_add_now (sched, &do_put, all_puts); | ||
756 | } | ||
757 | /** | ||
758 | * This function is called whenever a connection attempt is finished between two of | ||
759 | * the started peers (started with GNUNET_TESTING_daemons_start). The total | ||
760 | * number of times this function is called should equal the number returned | ||
761 | * from the GNUNET_TESTING_connect_topology call. | ||
762 | * | ||
763 | * The emsg variable is NULL on success (peers connected), and non-NULL on | ||
764 | * failure (peers failed to connect). | ||
765 | */ | ||
766 | void | ||
767 | topology_callback (void *cls, | ||
768 | const struct GNUNET_PeerIdentity *first, | ||
769 | const struct GNUNET_PeerIdentity *second, | ||
770 | uint32_t distance, | ||
771 | const struct GNUNET_CONFIGURATION_Handle *first_cfg, | ||
772 | const struct GNUNET_CONFIGURATION_Handle *second_cfg, | ||
773 | struct GNUNET_TESTING_Daemon *first_daemon, | ||
774 | struct GNUNET_TESTING_Daemon *second_daemon, | ||
775 | const char *emsg) | ||
776 | { | ||
777 | if (emsg == NULL) | ||
778 | { | ||
779 | total_connections++; | ||
780 | #if VERBOSE > 1 | ||
781 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n", | ||
782 | first_daemon->shortname, | ||
783 | second_daemon->shortname, | ||
784 | distance); | ||
785 | #endif | ||
786 | } | ||
787 | #if VERBOSE | ||
788 | else | ||
789 | { | ||
790 | failed_connections++; | ||
791 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n", | ||
792 | first_daemon->shortname, | ||
793 | second_daemon->shortname, emsg); | ||
794 | } | ||
795 | #endif | ||
796 | GNUNET_assert(peer_connect_meter != NULL); | ||
797 | if (GNUNET_YES == update_meter(peer_connect_meter)) | ||
798 | { | ||
799 | #if VERBOSE | ||
800 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
801 | "Created %d total connections, which is our target number! Starting next phase of testing.\n", | ||
802 | total_connections); | ||
803 | #endif | ||
804 | if (dhtlog_handle != NULL) | ||
805 | dhtlog_handle->update_connections (trialuid, total_connections); | ||
806 | |||
807 | GNUNET_SCHEDULER_cancel (sched, die_task); | ||
808 | die_task = GNUNET_SCHEDULER_add_delayed (sched, DEFAULT_TIMEOUT, | ||
809 | &end_badly, "from setup puts/gets"); | ||
810 | |||
811 | GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, settle_time), &setup_puts_and_gets, NULL); | ||
812 | } | ||
813 | else if (total_connections + failed_connections == expected_connections) | ||
814 | { | ||
815 | GNUNET_SCHEDULER_cancel (sched, die_task); | ||
816 | die_task = GNUNET_SCHEDULER_add_now (sched, | ||
817 | &end_badly, "from topology_callback (too many failed connections)"); | ||
818 | } | ||
819 | } | ||
820 | |||
821 | static void | ||
822 | peers_started_callback (void *cls, | ||
823 | const struct GNUNET_PeerIdentity *id, | ||
824 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
825 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
826 | { | ||
827 | if (emsg != NULL) | ||
828 | { | ||
829 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start daemon with error: `%s'\n", | ||
830 | emsg); | ||
831 | return; | ||
832 | } | ||
833 | GNUNET_assert (id != NULL); | ||
834 | |||
835 | #if VERBOSE > 1 | ||
836 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", | ||
837 | (num_peers - peers_left) + 1, num_peers); | ||
838 | #endif | ||
839 | |||
840 | peers_left--; | ||
841 | |||
842 | if (GNUNET_YES == update_meter(peer_start_meter)) | ||
843 | { | ||
844 | #if VERBOSE | ||
845 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
846 | "All %d daemons started, now connecting peers!\n", | ||
847 | num_peers); | ||
848 | #endif | ||
849 | GNUNET_SCHEDULER_cancel (sched, die_task); | ||
850 | |||
851 | expected_connections = -1; | ||
852 | if ((pg != NULL) && (peers_left == 0)) | ||
853 | { | ||
854 | expected_connections = GNUNET_TESTING_connect_topology (pg, connect_topology, connect_topology_option, connect_topology_option_modifier); | ||
855 | peer_connect_meter = create_meter(expected_connections, "Peer connection ", GNUNET_YES); | ||
856 | #if VERBOSE | ||
857 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
858 | "Have %d expected connections\n", expected_connections); | ||
859 | #endif | ||
860 | } | ||
861 | |||
862 | if (expected_connections == GNUNET_SYSERR) | ||
863 | { | ||
864 | die_task = GNUNET_SCHEDULER_add_now (sched, | ||
865 | &end_badly, "from connect topology (bad return)"); | ||
866 | } | ||
867 | |||
868 | die_task = GNUNET_SCHEDULER_add_delayed (sched, | ||
869 | GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, DEFAULT_CONNECT_TIMEOUT * expected_connections), | ||
870 | &end_badly, "from connect topology (timeout)"); | ||
871 | |||
872 | ok = 0; | ||
873 | } | ||
874 | } | ||
875 | |||
876 | static void | ||
877 | create_topology () | ||
878 | { | ||
879 | peers_left = num_peers; /* Reset counter */ | ||
880 | if (GNUNET_TESTING_create_topology (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) | ||
881 | { | ||
882 | #if VERBOSE | ||
883 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
884 | "Topology set up, now starting peers!\n"); | ||
885 | #endif | ||
886 | GNUNET_TESTING_daemons_continue_startup(pg); | ||
887 | } | ||
888 | else | ||
889 | { | ||
890 | GNUNET_SCHEDULER_cancel (sched, die_task); | ||
891 | die_task = GNUNET_SCHEDULER_add_now (sched, | ||
892 | &end_badly, "from create topology (bad return)"); | ||
893 | } | ||
894 | GNUNET_SCHEDULER_cancel (sched, die_task); | ||
895 | die_task = GNUNET_SCHEDULER_add_delayed (sched, | ||
896 | GNUNET_TIME_relative_multiply(seconds_per_peer_start, num_peers), | ||
897 | &end_badly, "from continue startup (timeout)"); | ||
898 | } | ||
899 | |||
900 | /** | ||
901 | * Callback indicating that the hostkey was created for a peer. | ||
902 | * | ||
903 | * @param cls NULL | ||
904 | * @param id the peer identity | ||
905 | * @param d the daemon handle (pretty useless at this point, remove?) | ||
906 | * @param emsg non-null on failure | ||
907 | */ | ||
908 | void hostkey_callback (void *cls, | ||
909 | const struct GNUNET_PeerIdentity *id, | ||
910 | struct GNUNET_TESTING_Daemon *d, | ||
911 | const char *emsg) | ||
912 | { | ||
913 | if (emsg != NULL) | ||
914 | { | ||
915 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Hostkey callback received error: %s\n", emsg); | ||
916 | } | ||
917 | |||
918 | #if VERBOSE > 1 | ||
919 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
920 | "Hostkey (%d/%d) created for peer `%s'\n", | ||
921 | num_peers - peers_left, num_peers, GNUNET_i2s(id)); | ||
922 | #endif | ||
923 | |||
924 | peers_left--; | ||
925 | if (GNUNET_YES == update_meter(hostkey_meter)) | ||
926 | { | ||
927 | #if VERBOSE | ||
928 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
929 | "All %d hostkeys created, now creating topology!\n", | ||
930 | num_peers); | ||
931 | #endif | ||
932 | GNUNET_SCHEDULER_cancel (sched, die_task); | ||
933 | /* Set up task in case topology creation doesn't finish | ||
934 | * within a reasonable amount of time */ | ||
935 | die_task = GNUNET_SCHEDULER_add_delayed (sched, | ||
936 | DEFAULT_TOPOLOGY_TIMEOUT, | ||
937 | &end_badly, "from create_topology"); | ||
938 | GNUNET_SCHEDULER_add_now(sched, &create_topology, NULL); | ||
939 | ok = 0; | ||
940 | } | ||
941 | } | ||
942 | |||
943 | |||
944 | static void | ||
945 | run (void *cls, | ||
946 | struct GNUNET_SCHEDULER_Handle *s, | ||
947 | char *const *args, | ||
948 | const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
949 | { | ||
950 | char * topology_str; | ||
951 | char * connect_topology_str; | ||
952 | char * blacklist_topology_str; | ||
953 | char * connect_topology_option_str; | ||
954 | char * connect_topology_option_modifier_string; | ||
955 | char *trialmessage; | ||
956 | char * topology_percentage_str; | ||
957 | float topology_percentage; | ||
958 | char * topology_probability_str; | ||
959 | float topology_probability; | ||
960 | unsigned long long temp_config_number; | ||
961 | |||
962 | sched = s; | ||
963 | |||
964 | /* Get path from configuration file */ | ||
965 | if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string(cfg, "paths", "servicehome", &test_directory)) | ||
966 | { | ||
967 | ok = 404; | ||
968 | return; | ||
969 | } | ||
970 | |||
971 | /** | ||
972 | * Get DHT specific testing options. | ||
973 | */ | ||
974 | if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht_testing", "mysql_logging"))|| | ||
975 | (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht_testing", "mysql_logging_extended"))) | ||
976 | { | ||
977 | dhtlog_handle = GNUNET_DHTLOG_connect(cfg); | ||
978 | if (dhtlog_handle == NULL) | ||
979 | { | ||
980 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
981 | "Could not connect to mysql server for logging, will NOT log dht operations!"); | ||
982 | ok = 3306; | ||
983 | return; | ||
984 | } | ||
985 | } | ||
986 | |||
987 | if (GNUNET_OK != | ||
988 | GNUNET_CONFIGURATION_get_value_string (cfg, "dht_testing", "comment", | ||
989 | &trialmessage)) | ||
990 | trialmessage = NULL; | ||
991 | |||
992 | if (GNUNET_OK != | ||
993 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "malicious_getters", | ||
994 | &malicious_getters)) | ||
995 | malicious_getters = 0; | ||
996 | |||
997 | if (GNUNET_OK != | ||
998 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "malicious_putters", | ||
999 | &malicious_putters)) | ||
1000 | malicious_putters = 0; | ||
1001 | |||
1002 | if (GNUNET_OK != | ||
1003 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "malicious_droppers", | ||
1004 | &malicious_droppers)) | ||
1005 | malicious_droppers = 0; | ||
1006 | |||
1007 | if (GNUNET_OK != | ||
1008 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "settle_time", | ||
1009 | &settle_time)) | ||
1010 | settle_time = 0; | ||
1011 | |||
1012 | if (GNUNET_SYSERR == | ||
1013 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "num_puts", | ||
1014 | &num_puts)) | ||
1015 | num_puts = num_peers; | ||
1016 | |||
1017 | if (GNUNET_SYSERR == | ||
1018 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "num_gets", | ||
1019 | &num_gets)) | ||
1020 | num_gets = num_peers; | ||
1021 | |||
1022 | if (GNUNET_OK == | ||
1023 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "get_timeout", | ||
1024 | &temp_config_number)) | ||
1025 | get_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number); | ||
1026 | else | ||
1027 | get_timeout = DEFAULT_GET_TIMEOUT; | ||
1028 | |||
1029 | if (GNUNET_OK == | ||
1030 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "concurrent_puts", | ||
1031 | &temp_config_number)) | ||
1032 | max_outstanding_puts = temp_config_number; | ||
1033 | else | ||
1034 | max_outstanding_puts = DEFAULT_MAX_OUTSTANDING_PUTS; | ||
1035 | |||
1036 | if (GNUNET_OK == | ||
1037 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "concurrent_gets", | ||
1038 | &temp_config_number)) | ||
1039 | max_outstanding_gets = temp_config_number; | ||
1040 | else | ||
1041 | max_outstanding_gets = DEFAULT_MAX_OUTSTANDING_GETS; | ||
1042 | |||
1043 | if (GNUNET_OK == | ||
1044 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "timeout", | ||
1045 | &temp_config_number)) | ||
1046 | all_get_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number); | ||
1047 | else | ||
1048 | all_get_timeout.value = get_timeout.value * ((num_gets / max_outstanding_gets) + 1); | ||
1049 | |||
1050 | if (GNUNET_OK == | ||
1051 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "get_delay", | ||
1052 | &temp_config_number)) | ||
1053 | get_delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number); | ||
1054 | else | ||
1055 | get_delay = DEFAULT_GET_DELAY; | ||
1056 | |||
1057 | if (GNUNET_OK == | ||
1058 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "put_delay", | ||
1059 | &temp_config_number)) | ||
1060 | put_delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number); | ||
1061 | else | ||
1062 | put_delay = DEFAULT_PUT_DELAY; | ||
1063 | |||
1064 | if (GNUNET_OK == | ||
1065 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "peer_start_timeout", | ||
1066 | &temp_config_number)) | ||
1067 | seconds_per_peer_start = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number); | ||
1068 | else | ||
1069 | seconds_per_peer_start = DEFAULT_SECONDS_PER_PEER_START; | ||
1070 | |||
1071 | if (GNUNET_OK == | ||
1072 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "data_size", | ||
1073 | &temp_config_number)) | ||
1074 | test_data_size = temp_config_number; | ||
1075 | else | ||
1076 | test_data_size = DEFAULT_TEST_DATA_SIZE; | ||
1077 | |||
1078 | /** | ||
1079 | * Get testing related options. | ||
1080 | */ | ||
1081 | if ((GNUNET_YES == | ||
1082 | GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "topology", | ||
1083 | &topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&topology, topology_str))) | ||
1084 | { | ||
1085 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1086 | "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "TOPOLOGY"); | ||
1087 | topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ | ||
1088 | } | ||
1089 | |||
1090 | if (GNUNET_OK != | ||
1091 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "percentage", | ||
1092 | &topology_percentage_str)) | ||
1093 | topology_percentage = 0.5; | ||
1094 | else | ||
1095 | { | ||
1096 | topology_percentage = atof (topology_percentage_str); | ||
1097 | } | ||
1098 | |||
1099 | if (GNUNET_OK != | ||
1100 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "probability", | ||
1101 | &topology_probability_str)) | ||
1102 | topology_probability = 0.5; | ||
1103 | else | ||
1104 | { | ||
1105 | topology_probability = atof (topology_probability_str); | ||
1106 | } | ||
1107 | |||
1108 | if ((GNUNET_YES == | ||
1109 | GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "connect_topology", | ||
1110 | &connect_topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&connect_topology, connect_topology_str))) | ||
1111 | { | ||
1112 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1113 | "Invalid connect topology `%s' given for section %s option %s\n", connect_topology_str, "TESTING", "CONNECT_TOPOLOGY"); | ||
1114 | } | ||
1115 | GNUNET_free_non_null(connect_topology_str); | ||
1116 | if ((GNUNET_YES == | ||
1117 | GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "connect_topology_option", | ||
1118 | &connect_topology_option_str)) && (GNUNET_NO == GNUNET_TESTING_topology_option_get(&connect_topology_option, connect_topology_option_str))) | ||
1119 | { | ||
1120 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1121 | "Invalid connect topology option `%s' given for section %s option %s\n", connect_topology_option_str, "TESTING", "CONNECT_TOPOLOGY_OPTION"); | ||
1122 | connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ | ||
1123 | } | ||
1124 | GNUNET_free_non_null(connect_topology_option_str); | ||
1125 | if (GNUNET_YES == | ||
1126 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology_option_modifier", | ||
1127 | &connect_topology_option_modifier_string)) | ||
1128 | { | ||
1129 | if (sscanf(connect_topology_option_modifier_string, "%lf", &connect_topology_option_modifier) != 1) | ||
1130 | { | ||
1131 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1132 | _("Invalid value `%s' for option `%s' in section `%s': expected float\n"), | ||
1133 | connect_topology_option_modifier_string, | ||
1134 | "connect_topology_option_modifier", | ||
1135 | "TESTING"); | ||
1136 | } | ||
1137 | GNUNET_free (connect_topology_option_modifier_string); | ||
1138 | } | ||
1139 | |||
1140 | if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "blacklist_transports", | ||
1141 | &blacklist_transports)) | ||
1142 | blacklist_transports = NULL; | ||
1143 | |||
1144 | if ((GNUNET_YES == | ||
1145 | GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "blacklist_topology", | ||
1146 | &blacklist_topology_str)) && | ||
1147 | (GNUNET_NO == GNUNET_TESTING_topology_get(&blacklist_topology, blacklist_topology_str))) | ||
1148 | { | ||
1149 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1150 | "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "BLACKLIST_TOPOLOGY"); | ||
1151 | } | ||
1152 | GNUNET_free_non_null(topology_str); | ||
1153 | GNUNET_free_non_null(blacklist_topology_str); | ||
1154 | |||
1155 | /* Get number of peers to start from configuration */ | ||
1156 | if (GNUNET_SYSERR == | ||
1157 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", | ||
1158 | &num_peers)) | ||
1159 | { | ||
1160 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1161 | "Number of peers must be specified in section %s option %s\n", topology_str, "TESTING", "NUM_PEERS"); | ||
1162 | } | ||
1163 | |||
1164 | /* Set peers_left so we know when all peers started */ | ||
1165 | peers_left = num_peers; | ||
1166 | |||
1167 | /* Set up a task to end testing if peer start fails */ | ||
1168 | die_task = GNUNET_SCHEDULER_add_delayed (sched, | ||
1169 | GNUNET_TIME_relative_multiply(seconds_per_peer_start, num_peers), | ||
1170 | &end_badly, "didn't generate all hostkeys within allowed startup time!"); | ||
1171 | |||
1172 | if (dhtlog_handle == NULL) | ||
1173 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1174 | "dhtlog_handle is NULL!"); | ||
1175 | |||
1176 | if ((trialmessage != NULL) && (dhtlog_handle != NULL)) | ||
1177 | { | ||
1178 | dhtlog_handle->insert_trial (&trialuid, peers_left, topology, | ||
1179 | blacklist_topology, connect_topology, | ||
1180 | connect_topology_option, | ||
1181 | connect_topology_option_modifier, topology_percentage, | ||
1182 | topology_probability, num_puts, num_gets, | ||
1183 | max_outstanding_gets, settle_time, 1, | ||
1184 | malicious_getters, malicious_putters, | ||
1185 | malicious_droppers, trialmessage); | ||
1186 | } | ||
1187 | else if (dhtlog_handle != NULL) | ||
1188 | { | ||
1189 | dhtlog_handle->insert_trial (&trialuid, peers_left, topology, | ||
1190 | blacklist_topology, connect_topology, | ||
1191 | connect_topology_option, | ||
1192 | connect_topology_option_modifier, topology_percentage, | ||
1193 | topology_probability, num_puts, num_gets, | ||
1194 | max_outstanding_gets, settle_time, 1, | ||
1195 | malicious_getters, malicious_putters, | ||
1196 | malicious_droppers, ""); | ||
1197 | } | ||
1198 | |||
1199 | hostkey_meter = create_meter(peers_left, "Hostkeys created ", GNUNET_YES); | ||
1200 | peer_start_meter = create_meter(peers_left, "Peers started ", GNUNET_YES); | ||
1201 | |||
1202 | put_meter = create_meter(num_gets, "Puts completed ", GNUNET_YES); | ||
1203 | get_meter = create_meter(num_gets, "Gets completed ", GNUNET_YES); | ||
1204 | pg = GNUNET_TESTING_daemons_start (sched, cfg, | ||
1205 | peers_left, | ||
1206 | GNUNET_TIME_relative_multiply(seconds_per_peer_start, num_peers), | ||
1207 | &hostkey_callback, NULL, | ||
1208 | &peers_started_callback, NULL, | ||
1209 | &topology_callback, NULL, | ||
1210 | NULL); | ||
1211 | |||
1212 | } | ||
1213 | |||
1214 | |||
1215 | int | ||
1216 | main (int argc, char *argv[]) | ||
1217 | { | ||
1218 | int ret; | ||
1219 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
1220 | GNUNET_GETOPT_OPTION_END | ||
1221 | }; | ||
1222 | |||
1223 | ret = GNUNET_PROGRAM_run (argc, | ||
1224 | argv, "gnunet-dht-driver", "nohelp", | ||
1225 | options, &run, &ok); | ||
1226 | |||
1227 | if (ret != GNUNET_OK) | ||
1228 | { | ||
1229 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "`gnunet-dht-driver': Failed with error code %d\n", ret); | ||
1230 | } | ||
1231 | |||
1232 | /** | ||
1233 | * Need to remove base directory, subdirectories taken care | ||
1234 | * of by the testing framework. | ||
1235 | */ | ||
1236 | if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) | ||
1237 | { | ||
1238 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory); | ||
1239 | } | ||
1240 | return ret; | ||
1241 | } | ||
1242 | |||
1243 | /* end of test_dht_twopeer_put_get.c */ | ||
diff --git a/src/dht/gnunet-service-dht.c b/src/dht/gnunet-service-dht.c index 32c01e384..eca3131b0 100644 --- a/src/dht/gnunet-service-dht.c +++ b/src/dht/gnunet-service-dht.c | |||
@@ -313,7 +313,7 @@ send_reply_to_client (struct ClientList *client, | |||
313 | pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + tsize); | 313 | pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + tsize); |
314 | pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1]; | 314 | pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1]; |
315 | reply = (struct GNUNET_DHT_RouteResultMessage *)&pending_message[1]; | 315 | reply = (struct GNUNET_DHT_RouteResultMessage *)&pending_message[1]; |
316 | reply->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_ROUTE_RESULT); | 316 | reply->header.type = htons (GNUNET_MESSAGE_TYPE_LOCAL_DHT_ROUTE_RESULT); |
317 | reply->header.size = htons (tsize); | 317 | reply->header.size = htons (tsize); |
318 | reply->unique_id = GNUNET_htonll (uid); | 318 | reply->unique_id = GNUNET_htonll (uid); |
319 | memcpy (&reply[1], message, msize); | 319 | memcpy (&reply[1], message, msize); |
@@ -353,7 +353,6 @@ datacache_get_iterator (void *cls, | |||
353 | get_result->header.size = | 353 | get_result->header.size = |
354 | htons (sizeof (struct GNUNET_DHT_GetResultMessage) + size); | 354 | htons (sizeof (struct GNUNET_DHT_GetResultMessage) + size); |
355 | get_result->expiration = exp; | 355 | get_result->expiration = exp; |
356 | memcpy (&get_result->key, key, sizeof (GNUNET_HashCode)); | ||
357 | get_result->type = htons (type); | 356 | get_result->type = htons (type); |
358 | memcpy (&get_result[1], data, size); | 357 | memcpy (&get_result[1], data, size); |
359 | send_reply_to_client (datacache_get_ctx->client, &get_result->header, | 358 | send_reply_to_client (datacache_get_ctx->client, &get_result->header, |
@@ -573,7 +572,7 @@ handle_dht_start_message (void *cls, struct GNUNET_SERVER_Client *client, | |||
573 | * be processed everywhere _AND_ we want it processed everywhere, then | 572 | * be processed everywhere _AND_ we want it processed everywhere, then |
574 | * handle it locally. | 573 | * handle it locally. |
575 | */ | 574 | */ |
576 | handle_locally = GNUNET_YES; | 575 | handle_locally = GNUNET_NO; |
577 | if (handle_locally == GNUNET_YES) | 576 | if (handle_locally == GNUNET_YES) |
578 | { | 577 | { |
579 | switch (enc_type) | 578 | switch (enc_type) |
@@ -596,6 +595,9 @@ handle_dht_start_message (void *cls, struct GNUNET_SERVER_Client *client, | |||
596 | "`%s': Message type (%d) not handled\n", "DHT", enc_type); | 595 | "`%s': Message type (%d) not handled\n", "DHT", enc_type); |
597 | } | 596 | } |
598 | } | 597 | } |
598 | else | ||
599 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
600 | "`%s': Message type (%d) not handled\n", "DHT", enc_type); | ||
599 | GNUNET_free (message_context); | 601 | GNUNET_free (message_context); |
600 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 602 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
601 | 603 | ||
@@ -759,15 +761,15 @@ core_init (void *cls, | |||
759 | 761 | ||
760 | 762 | ||
761 | static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = { | 763 | static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = { |
762 | {&handle_dht_start_message, NULL, GNUNET_MESSAGE_TYPE_DHT_ROUTE, 0}, | 764 | {&handle_dht_start_message, NULL, GNUNET_MESSAGE_TYPE_LOCAL_DHT_ROUTE, 0}, |
763 | {&handle_dht_stop_message, NULL, GNUNET_MESSAGE_TYPE_DHT_STOP, 0}, | 765 | {&handle_dht_stop_message, NULL, GNUNET_MESSAGE_TYPE_DHT_ROUTE_STOP, 0}, |
764 | {NULL, NULL, 0, 0} | 766 | {NULL, NULL, 0, 0} |
765 | }; | 767 | }; |
766 | 768 | ||
767 | 769 | ||
768 | static struct GNUNET_CORE_MessageHandler core_handlers[] = { | 770 | static struct GNUNET_CORE_MessageHandler core_handlers[] = { |
769 | {&handle_dht_p2p_route_request, GNUNET_MESSAGE_TYPE_DHT_ROUTE, 0}, | 771 | {&handle_dht_p2p_route_request, GNUNET_MESSAGE_TYPE_P2P_DHT_ROUTE, 0}, |
770 | {&handle_dht_p2p_route_result, GNUNET_MESSAGE_TYPE_DHT_ROUTE_RESULT, 0}, | 772 | {&handle_dht_p2p_route_result, GNUNET_MESSAGE_TYPE_P2P_DHT_ROUTE_RESULT, 0}, |
771 | {NULL, 0, 0} | 773 | {NULL, 0, 0} |
772 | }; | 774 | }; |
773 | 775 | ||
diff --git a/src/dht/test_dht_api_data.conf b/src/dht/test_dht_api_data.conf index 047b2ea3d..0dcd95691 100644 --- a/src/dht/test_dht_api_data.conf +++ b/src/dht/test_dht_api_data.conf | |||
@@ -58,10 +58,10 @@ HOSTNAME = localhost | |||
58 | PORT = 2092 | 58 | PORT = 2092 |
59 | 59 | ||
60 | [dht] | 60 | [dht] |
61 | DEBUG = NO | 61 | DEBUG = YES |
62 | ACCEPT_FROM6 = ::1; | 62 | ACCEPT_FROM6 = ::1; |
63 | ACCEPT_FROM = 127.0.0.1; | 63 | ACCEPT_FROM = 127.0.0.1; |
64 | BINARY = gnunet-service-dht | 64 | BINARY = gnunet-service-dht-new |
65 | CONFIG = $DEFAULTCONFIG | 65 | CONFIG = $DEFAULTCONFIG |
66 | HOME = $SERVICEHOME | 66 | HOME = $SERVICEHOME |
67 | HOSTNAME = localhost | 67 | HOSTNAME = localhost |
diff --git a/src/dht/test_dht_multipeer.c b/src/dht/test_dht_multipeer.c new file mode 100644 index 000000000..3762bdaf9 --- /dev/null +++ b/src/dht/test_dht_multipeer.c | |||
@@ -0,0 +1,915 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file dht/test_dht_multipeer.c | ||
22 | * @brief testcase for testing DHT service with | ||
23 | * multiple peers. | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_testing_lib.h" | ||
27 | #include "gnunet_core_service.h" | ||
28 | #include "gnunet_dht_service.h" | ||
29 | |||
30 | /* DEFINES */ | ||
31 | #define VERBOSE GNUNET_YES | ||
32 | |||
33 | /* Timeout for entire testcase */ | ||
34 | #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5) | ||
35 | |||
36 | /* Timeout for waiting for replies to get requests */ | ||
37 | #define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90) | ||
38 | |||
39 | /* Timeout for waiting for gets to complete */ | ||
40 | #define GET_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1) | ||
41 | |||
42 | /* Timeout for waiting for puts to complete */ | ||
43 | #define PUT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1) | ||
44 | |||
45 | #define SECONDS_PER_PEER_START 45 | ||
46 | |||
47 | /* If number of peers not in config file, use this number */ | ||
48 | #define DEFAULT_NUM_PEERS 5 | ||
49 | |||
50 | #define TEST_DATA_SIZE 8 | ||
51 | |||
52 | #define MAX_OUTSTANDING_PUTS 10 | ||
53 | |||
54 | #define MAX_OUTSTANDING_GETS 10 | ||
55 | |||
56 | /* Structs */ | ||
57 | |||
58 | struct TestPutContext | ||
59 | { | ||
60 | /* This is a linked list */ | ||
61 | struct TestPutContext *next; | ||
62 | |||
63 | /** | ||
64 | * Handle to the first peers DHT service (via the API) | ||
65 | */ | ||
66 | struct GNUNET_DHT_Handle *dht_handle; | ||
67 | |||
68 | /** | ||
69 | * Handle to the PUT peer daemon | ||
70 | */ | ||
71 | struct GNUNET_TESTING_Daemon *daemon; | ||
72 | |||
73 | /** | ||
74 | * Identifier for this PUT | ||
75 | */ | ||
76 | uint32_t uid; | ||
77 | |||
78 | /** | ||
79 | * Task for disconnecting DHT handles | ||
80 | */ | ||
81 | GNUNET_SCHEDULER_TaskIdentifier disconnect_task; | ||
82 | }; | ||
83 | |||
84 | struct TestGetContext | ||
85 | { | ||
86 | /* This is a linked list */ | ||
87 | struct TestGetContext *next; | ||
88 | |||
89 | /** | ||
90 | * Handle to the first peers DHT service (via the API) | ||
91 | */ | ||
92 | struct GNUNET_DHT_Handle *dht_handle; | ||
93 | |||
94 | /** | ||
95 | * Handle for the DHT get request | ||
96 | */ | ||
97 | struct GNUNET_DHT_GetHandle *get_handle; | ||
98 | |||
99 | /** | ||
100 | * Handle to the GET peer daemon | ||
101 | */ | ||
102 | struct GNUNET_TESTING_Daemon *daemon; | ||
103 | |||
104 | /** | ||
105 | * Identifier for this GET | ||
106 | */ | ||
107 | uint32_t uid; | ||
108 | |||
109 | /** | ||
110 | * Task for disconnecting DHT handles (and stopping GET) | ||
111 | */ | ||
112 | GNUNET_SCHEDULER_TaskIdentifier disconnect_task; | ||
113 | |||
114 | /** | ||
115 | * Whether or not this request has been fulfilled already. | ||
116 | */ | ||
117 | int succeeded; | ||
118 | }; | ||
119 | |||
120 | /* Globals */ | ||
121 | |||
122 | /** | ||
123 | * List of GETS to perform | ||
124 | */ | ||
125 | struct TestGetContext *all_gets; | ||
126 | |||
127 | /** | ||
128 | * List of PUTS to perform | ||
129 | */ | ||
130 | struct TestPutContext *all_puts; | ||
131 | |||
132 | /** | ||
133 | * Directory to store temp data in, defined in config file | ||
134 | */ | ||
135 | static char *test_directory; | ||
136 | |||
137 | /** | ||
138 | * Variable used to store the number of connections we should wait for. | ||
139 | */ | ||
140 | static unsigned int expected_connections; | ||
141 | |||
142 | /** | ||
143 | * Variable used to keep track of how many peers aren't yet started. | ||
144 | */ | ||
145 | static unsigned long long peers_left; | ||
146 | |||
147 | /** | ||
148 | * Handle to the set of all peers run for this test. | ||
149 | */ | ||
150 | static struct GNUNET_TESTING_PeerGroup *pg; | ||
151 | |||
152 | |||
153 | /** | ||
154 | * Global scheduler, used for all GNUNET_SCHEDULER_* functions. | ||
155 | */ | ||
156 | static struct GNUNET_SCHEDULER_Handle *sched; | ||
157 | |||
158 | /** | ||
159 | * Total number of peers to run, set based on config file. | ||
160 | */ | ||
161 | static unsigned long long num_peers; | ||
162 | |||
163 | /** | ||
164 | * Total number of items to insert. | ||
165 | */ | ||
166 | static unsigned long long num_puts; | ||
167 | |||
168 | /** | ||
169 | * Total number of items to attempt to get. | ||
170 | */ | ||
171 | static unsigned long long num_gets; | ||
172 | |||
173 | /** | ||
174 | * How many puts do we currently have in flight? | ||
175 | */ | ||
176 | static unsigned long long outstanding_puts; | ||
177 | |||
178 | /** | ||
179 | * How many puts are done? | ||
180 | */ | ||
181 | static unsigned long long puts_completed; | ||
182 | |||
183 | /** | ||
184 | * How many puts do we currently have in flight? | ||
185 | */ | ||
186 | static unsigned long long outstanding_gets; | ||
187 | |||
188 | /** | ||
189 | * How many gets are done? | ||
190 | */ | ||
191 | static unsigned long long gets_completed; | ||
192 | |||
193 | /** | ||
194 | * How many gets failed? | ||
195 | */ | ||
196 | static unsigned long long gets_failed; | ||
197 | |||
198 | /** | ||
199 | * Global used to count how many connections we have currently | ||
200 | * been notified about (how many times has topology_callback been called | ||
201 | * with success?) | ||
202 | */ | ||
203 | static unsigned int total_connections; | ||
204 | |||
205 | /** | ||
206 | * Global used to count how many failed connections we have | ||
207 | * been notified about (how many times has topology_callback | ||
208 | * been called with failure?) | ||
209 | */ | ||
210 | static unsigned int failed_connections; | ||
211 | |||
212 | /* Task handle to use to schedule test failure */ | ||
213 | GNUNET_SCHEDULER_TaskIdentifier die_task; | ||
214 | |||
215 | static char *blacklist_transports; | ||
216 | |||
217 | static enum GNUNET_TESTING_Topology topology; | ||
218 | |||
219 | static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */ | ||
220 | |||
221 | static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ | ||
222 | |||
223 | static enum GNUNET_TESTING_TopologyOption connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; | ||
224 | |||
225 | static double connect_topology_option_modifier = 0.0; | ||
226 | |||
227 | /* Global return value (0 for success, anything else for failure) */ | ||
228 | static int ok; | ||
229 | |||
230 | |||
231 | /** | ||
232 | * Check whether peers successfully shut down. | ||
233 | */ | ||
234 | void shutdown_callback (void *cls, | ||
235 | const char *emsg) | ||
236 | { | ||
237 | if (emsg != NULL) | ||
238 | { | ||
239 | if (ok == 0) | ||
240 | ok = 2; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * Task to release DHT handles for PUT | ||
246 | */ | ||
247 | static void | ||
248 | put_disconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
249 | { | ||
250 | struct TestPutContext *test_put = cls; | ||
251 | test_put->disconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
252 | GNUNET_DHT_disconnect(test_put->dht_handle); | ||
253 | test_put->dht_handle = NULL; | ||
254 | } | ||
255 | |||
256 | /** | ||
257 | * Function scheduled to be run on the successful completion of this | ||
258 | * testcase. | ||
259 | */ | ||
260 | static void | ||
261 | finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
262 | { | ||
263 | GNUNET_assert (pg != NULL); | ||
264 | struct TestPutContext *test_put = all_puts; | ||
265 | struct TestGetContext *test_get = all_gets; | ||
266 | |||
267 | while (test_put != NULL) | ||
268 | { | ||
269 | if (test_put->disconnect_task != GNUNET_SCHEDULER_NO_TASK) | ||
270 | GNUNET_SCHEDULER_cancel(sched, test_put->disconnect_task); | ||
271 | if (test_put->dht_handle != NULL) | ||
272 | GNUNET_DHT_disconnect(test_put->dht_handle); | ||
273 | test_put = test_put->next; | ||
274 | } | ||
275 | |||
276 | while (test_get != NULL) | ||
277 | { | ||
278 | if (test_get->disconnect_task != GNUNET_SCHEDULER_NO_TASK) | ||
279 | GNUNET_SCHEDULER_cancel(sched, test_get->disconnect_task); | ||
280 | if (test_get->get_handle != NULL) | ||
281 | GNUNET_DHT_get_stop(test_get->get_handle, NULL, NULL); | ||
282 | if (test_get->dht_handle != NULL) | ||
283 | GNUNET_DHT_disconnect(test_get->dht_handle); | ||
284 | test_get = test_get->next; | ||
285 | } | ||
286 | |||
287 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
288 | ok = 0; | ||
289 | } | ||
290 | |||
291 | |||
292 | /** | ||
293 | * Check if the get_handle is being used, if so stop the request. Either | ||
294 | * way, schedule the end_badly_cont function which actually shuts down the | ||
295 | * test. | ||
296 | */ | ||
297 | static void | ||
298 | end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
299 | { | ||
300 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failing test with error: `%s'!\n", (char *)cls); | ||
301 | |||
302 | struct TestPutContext *test_put = all_puts; | ||
303 | struct TestGetContext *test_get = all_gets; | ||
304 | |||
305 | while (test_put != NULL) | ||
306 | { | ||
307 | if (test_put->disconnect_task != GNUNET_SCHEDULER_NO_TASK) | ||
308 | GNUNET_SCHEDULER_cancel(sched, test_put->disconnect_task); | ||
309 | if (test_put->dht_handle != NULL) | ||
310 | GNUNET_DHT_disconnect(test_put->dht_handle); | ||
311 | test_put = test_put->next; | ||
312 | } | ||
313 | |||
314 | while (test_get != NULL) | ||
315 | { | ||
316 | if (test_get->disconnect_task != GNUNET_SCHEDULER_NO_TASK) | ||
317 | GNUNET_SCHEDULER_cancel(sched, test_get->disconnect_task); | ||
318 | if (test_get->get_handle != NULL) | ||
319 | GNUNET_DHT_get_stop(test_get->get_handle, NULL, NULL); | ||
320 | if (test_get->dht_handle != NULL) | ||
321 | GNUNET_DHT_disconnect(test_get->dht_handle); | ||
322 | test_get = test_get->next; | ||
323 | } | ||
324 | |||
325 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
326 | ok = 1; | ||
327 | } | ||
328 | |||
329 | /** | ||
330 | * Task to release DHT handle associated with GET request. | ||
331 | */ | ||
332 | static void | ||
333 | get_stop_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
334 | { | ||
335 | struct TestGetContext *test_get = cls; | ||
336 | outstanding_gets--; /* GET is really finished */ | ||
337 | GNUNET_DHT_disconnect(test_get->dht_handle); | ||
338 | test_get->dht_handle = NULL; | ||
339 | |||
340 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%d gets succeeded, %d gets failed!\n", gets_completed, gets_failed); | ||
341 | if ((gets_completed == num_gets) && (outstanding_gets == 0))/* All gets successful */ | ||
342 | { | ||
343 | GNUNET_SCHEDULER_cancel(sched, die_task); | ||
344 | GNUNET_SCHEDULER_add_now(sched, &finish_testing, NULL); | ||
345 | } | ||
346 | else if ((gets_completed + gets_failed == num_gets) && (outstanding_gets == 0)) /* Had some failures */ | ||
347 | { | ||
348 | GNUNET_SCHEDULER_cancel(sched, die_task); | ||
349 | GNUNET_SCHEDULER_add_now(sched, &end_badly, "not all gets succeeded!\n"); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | /** | ||
354 | * Task to release get handle. | ||
355 | */ | ||
356 | static void | ||
357 | get_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
358 | { | ||
359 | struct TestGetContext *test_get = cls; | ||
360 | GNUNET_HashCode search_key; /* Key stored under */ | ||
361 | char original_data[TEST_DATA_SIZE]; /* Made up data to store */ | ||
362 | |||
363 | memset(original_data, test_get->uid, sizeof(original_data)); | ||
364 | GNUNET_CRYPTO_hash(original_data, TEST_DATA_SIZE, &search_key); | ||
365 | |||
366 | if (tc->reason == GNUNET_SCHEDULER_REASON_TIMEOUT) | ||
367 | { | ||
368 | gets_failed++; | ||
369 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get from peer %s for key %s failed!\n", test_get->daemon->shortname, GNUNET_h2s(&search_key)); | ||
370 | } | ||
371 | GNUNET_assert(test_get->get_handle != NULL); | ||
372 | GNUNET_DHT_get_stop(test_get->get_handle, &get_stop_finished, test_get); | ||
373 | test_get->get_handle = NULL; | ||
374 | test_get->disconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
375 | } | ||
376 | |||
377 | /** | ||
378 | * Iterator called if the GET request initiated returns a response. | ||
379 | * | ||
380 | * @param cls closure | ||
381 | * @param exp when will this value expire | ||
382 | * @param key key of the result | ||
383 | * @param type type of the result | ||
384 | * @param size number of bytes in data | ||
385 | * @param data pointer to the result data | ||
386 | */ | ||
387 | void get_result_iterator (void *cls, | ||
388 | struct GNUNET_TIME_Absolute exp, | ||
389 | const GNUNET_HashCode * key, | ||
390 | uint32_t type, | ||
391 | uint32_t size, | ||
392 | const void *data) | ||
393 | { | ||
394 | struct TestGetContext *test_get = cls; | ||
395 | GNUNET_HashCode search_key; /* Key stored under */ | ||
396 | char original_data[TEST_DATA_SIZE]; /* Made up data to store */ | ||
397 | |||
398 | memset(original_data, test_get->uid, sizeof(original_data)); | ||
399 | GNUNET_CRYPTO_hash(original_data, TEST_DATA_SIZE, &search_key); | ||
400 | |||
401 | if (test_get->succeeded == GNUNET_YES) | ||
402 | return; /* Get has already been successful, probably ending now */ | ||
403 | |||
404 | if ((0 != memcmp(&search_key, key, sizeof (GNUNET_HashCode))) || (0 != memcmp(original_data, data, sizeof(original_data)))) | ||
405 | { | ||
406 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Key or data is not the same as was inserted!\n"); | ||
407 | } | ||
408 | else | ||
409 | { | ||
410 | gets_completed++; | ||
411 | test_get->succeeded = GNUNET_YES; | ||
412 | } | ||
413 | |||
414 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct GET response!\n"); | ||
415 | GNUNET_SCHEDULER_cancel(sched, test_get->disconnect_task); | ||
416 | GNUNET_SCHEDULER_add_continuation(sched, &get_stop_task, test_get, GNUNET_SCHEDULER_REASON_PREREQ_DONE); | ||
417 | } | ||
418 | |||
419 | /** | ||
420 | * Continuation telling us GET request was sent. | ||
421 | */ | ||
422 | static void | ||
423 | get_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
424 | { | ||
425 | // Is there something to be done here? | ||
426 | if (tc->reason != GNUNET_SCHEDULER_REASON_PREREQ_DONE) | ||
427 | return; | ||
428 | } | ||
429 | |||
430 | /** | ||
431 | * Set up some data, and call API PUT function | ||
432 | */ | ||
433 | static void | ||
434 | do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
435 | { | ||
436 | struct TestGetContext *test_get = cls; | ||
437 | GNUNET_HashCode key; /* Made up key to store data under */ | ||
438 | char data[TEST_DATA_SIZE]; /* Made up data to store */ | ||
439 | |||
440 | if (test_get == NULL) | ||
441 | return; /* End of the list */ | ||
442 | memset(data, test_get->uid, sizeof(data)); | ||
443 | GNUNET_CRYPTO_hash(data, TEST_DATA_SIZE, &key); | ||
444 | |||
445 | if (outstanding_gets > MAX_OUTSTANDING_GETS) | ||
446 | { | ||
447 | GNUNET_SCHEDULER_add_delayed (sched, GET_DELAY, &do_get, test_get); | ||
448 | return; | ||
449 | } | ||
450 | |||
451 | test_get->dht_handle = GNUNET_DHT_connect(sched, test_get->daemon->cfg, 10); | ||
452 | /* Insert the data at the first peer */ | ||
453 | GNUNET_assert(test_get->dht_handle != NULL); | ||
454 | outstanding_gets++; | ||
455 | test_get->get_handle = GNUNET_DHT_get_start(test_get->dht_handle, | ||
456 | GNUNET_TIME_relative_get_forever(), | ||
457 | 1, | ||
458 | &key, | ||
459 | &get_result_iterator, | ||
460 | test_get, | ||
461 | &get_continuation, | ||
462 | test_get); | ||
463 | #if VERBOSE | ||
464 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting get for uid %u from peer %s\n", | ||
465 | test_get->uid, | ||
466 | test_get->daemon->shortname); | ||
467 | #endif | ||
468 | test_get->disconnect_task = GNUNET_SCHEDULER_add_delayed(sched, GET_TIMEOUT, &get_stop_task, test_get); | ||
469 | GNUNET_SCHEDULER_add_now (sched, &do_get, test_get->next); | ||
470 | } | ||
471 | |||
472 | /** | ||
473 | * Called when the PUT request has been transmitted to the DHT service. | ||
474 | * Schedule the GET request for some time in the future. | ||
475 | */ | ||
476 | static void | ||
477 | put_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
478 | { | ||
479 | struct TestPutContext *test_put = cls; | ||
480 | outstanding_puts--; | ||
481 | puts_completed++; | ||
482 | |||
483 | GNUNET_SCHEDULER_cancel(sched, test_put->disconnect_task); | ||
484 | test_put->disconnect_task = GNUNET_SCHEDULER_add_now(sched, &put_disconnect_task, test_put); | ||
485 | if (puts_completed == num_puts) | ||
486 | { | ||
487 | GNUNET_assert(outstanding_puts == 0); | ||
488 | GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10), &do_get, all_gets); | ||
489 | return; | ||
490 | } | ||
491 | } | ||
492 | |||
493 | /** | ||
494 | * Set up some data, and call API PUT function | ||
495 | */ | ||
496 | static void | ||
497 | do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
498 | { | ||
499 | struct TestPutContext *test_put = cls; | ||
500 | GNUNET_HashCode key; /* Made up key to store data under */ | ||
501 | char data[TEST_DATA_SIZE]; /* Made up data to store */ | ||
502 | |||
503 | if (test_put == NULL) | ||
504 | return; /* End of list */ | ||
505 | |||
506 | memset(data, test_put->uid, sizeof(data)); | ||
507 | GNUNET_CRYPTO_hash(data, TEST_DATA_SIZE, &key); | ||
508 | |||
509 | if (outstanding_puts > MAX_OUTSTANDING_PUTS) | ||
510 | { | ||
511 | GNUNET_SCHEDULER_add_delayed (sched, PUT_DELAY, &do_put, test_put); | ||
512 | return; | ||
513 | } | ||
514 | |||
515 | #if VERBOSE | ||
516 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting put for uid %u from peer %s\n", | ||
517 | test_put->uid, | ||
518 | test_put->daemon->shortname); | ||
519 | #endif | ||
520 | test_put->dht_handle = GNUNET_DHT_connect(sched, test_put->daemon->cfg, 10); | ||
521 | |||
522 | GNUNET_assert(test_put->dht_handle != NULL); | ||
523 | outstanding_puts++; | ||
524 | GNUNET_DHT_put(test_put->dht_handle, | ||
525 | &key, | ||
526 | 1, | ||
527 | sizeof(data), data, | ||
528 | GNUNET_TIME_absolute_get_forever(), | ||
529 | GNUNET_TIME_relative_get_forever(), | ||
530 | &put_finished, test_put); | ||
531 | test_put->disconnect_task = GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_get_forever(), &put_disconnect_task, test_put); | ||
532 | GNUNET_SCHEDULER_add_now(sched, &do_put, test_put->next); | ||
533 | } | ||
534 | |||
535 | |||
536 | /** | ||
537 | * Set up some all of the put and get operations we want | ||
538 | * to do. Allocate data structure for each, add to list, | ||
539 | * then call actual insert functions. | ||
540 | */ | ||
541 | static void | ||
542 | setup_puts_and_gets (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) | ||
543 | { | ||
544 | int i; | ||
545 | uint32_t temp_daemon; | ||
546 | struct TestPutContext *test_put; | ||
547 | struct TestGetContext *test_get; | ||
548 | int remember[num_puts][num_peers]; | ||
549 | |||
550 | for (i = 0; i < num_puts; i++) | ||
551 | { | ||
552 | test_put = GNUNET_malloc(sizeof(struct TestPutContext)); | ||
553 | test_put->uid = i; | ||
554 | temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers); | ||
555 | test_put->daemon = GNUNET_TESTING_daemon_get(pg, temp_daemon); | ||
556 | test_put->next = all_puts; | ||
557 | all_puts = test_put; | ||
558 | } | ||
559 | |||
560 | for (i = 0; i < num_gets; i++) | ||
561 | { | ||
562 | test_get = GNUNET_malloc(sizeof(struct TestGetContext)); | ||
563 | test_get->uid = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_puts); | ||
564 | temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers); | ||
565 | while (remember[test_get->uid][temp_daemon] == 1) | ||
566 | temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers); | ||
567 | test_get->daemon = GNUNET_TESTING_daemon_get(pg, temp_daemon); | ||
568 | remember[test_get->uid][temp_daemon] = 1; | ||
569 | test_get->next = all_gets; | ||
570 | all_gets = test_get; | ||
571 | } | ||
572 | |||
573 | GNUNET_SCHEDULER_add_now (sched, &do_put, all_puts); | ||
574 | } | ||
575 | /** | ||
576 | * This function is called whenever a connection attempt is finished between two of | ||
577 | * the started peers (started with GNUNET_TESTING_daemons_start). The total | ||
578 | * number of times this function is called should equal the number returned | ||
579 | * from the GNUNET_TESTING_connect_topology call. | ||
580 | * | ||
581 | * The emsg variable is NULL on success (peers connected), and non-NULL on | ||
582 | * failure (peers failed to connect). | ||
583 | */ | ||
584 | void | ||
585 | topology_callback (void *cls, | ||
586 | const struct GNUNET_PeerIdentity *first, | ||
587 | const struct GNUNET_PeerIdentity *second, | ||
588 | uint32_t distance, | ||
589 | const struct GNUNET_CONFIGURATION_Handle *first_cfg, | ||
590 | const struct GNUNET_CONFIGURATION_Handle *second_cfg, | ||
591 | struct GNUNET_TESTING_Daemon *first_daemon, | ||
592 | struct GNUNET_TESTING_Daemon *second_daemon, | ||
593 | const char *emsg) | ||
594 | { | ||
595 | if (emsg == NULL) | ||
596 | { | ||
597 | total_connections++; | ||
598 | #if VERBOSE > 1 | ||
599 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n", | ||
600 | first_daemon->shortname, | ||
601 | second_daemon->shortname, | ||
602 | distance); | ||
603 | #endif | ||
604 | } | ||
605 | #if VERBOSE | ||
606 | else | ||
607 | { | ||
608 | failed_connections++; | ||
609 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n", | ||
610 | first_daemon->shortname, | ||
611 | second_daemon->shortname, emsg); | ||
612 | } | ||
613 | #endif | ||
614 | |||
615 | if (total_connections == expected_connections) | ||
616 | { | ||
617 | #if VERBOSE | ||
618 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
619 | "Created %d total connections, which is our target number! Starting next phase of testing.\n", | ||
620 | total_connections); | ||
621 | #endif | ||
622 | GNUNET_SCHEDULER_cancel (sched, die_task); | ||
623 | die_task = GNUNET_SCHEDULER_add_delayed (sched, TIMEOUT, | ||
624 | &end_badly, "from setup puts/gets"); | ||
625 | |||
626 | GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 2), &setup_puts_and_gets, NULL); | ||
627 | } | ||
628 | else if (total_connections + failed_connections == expected_connections) | ||
629 | { | ||
630 | GNUNET_SCHEDULER_cancel (sched, die_task); | ||
631 | die_task = GNUNET_SCHEDULER_add_now (sched, | ||
632 | &end_badly, "from topology_callback (too many failed connections)"); | ||
633 | } | ||
634 | } | ||
635 | |||
636 | static void | ||
637 | peers_started_callback (void *cls, | ||
638 | const struct GNUNET_PeerIdentity *id, | ||
639 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
640 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
641 | { | ||
642 | if (emsg != NULL) | ||
643 | { | ||
644 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start daemon with error: `%s'\n", | ||
645 | emsg); | ||
646 | return; | ||
647 | } | ||
648 | GNUNET_assert (id != NULL); | ||
649 | |||
650 | #if VERBOSE | ||
651 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", | ||
652 | (num_peers - peers_left) + 1, num_peers); | ||
653 | #endif | ||
654 | |||
655 | peers_left--; | ||
656 | if (peers_left == 0) | ||
657 | { | ||
658 | |||
659 | #if VERBOSE | ||
660 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
661 | "All %d daemons started, now connecting peers!\n", | ||
662 | num_peers); | ||
663 | #endif | ||
664 | GNUNET_SCHEDULER_cancel (sched, die_task); | ||
665 | |||
666 | expected_connections = -1; | ||
667 | if ((pg != NULL) && (peers_left == 0)) | ||
668 | { | ||
669 | expected_connections = GNUNET_TESTING_connect_topology (pg, connection_topology, connect_topology_option, connect_topology_option_modifier); | ||
670 | #if VERBOSE | ||
671 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
672 | "Have %d expected connections\n", expected_connections); | ||
673 | #endif | ||
674 | } | ||
675 | |||
676 | if (expected_connections == GNUNET_SYSERR) | ||
677 | { | ||
678 | die_task = GNUNET_SCHEDULER_add_now (sched, | ||
679 | &end_badly, "from connect topology (bad return)"); | ||
680 | } | ||
681 | |||
682 | die_task = GNUNET_SCHEDULER_add_delayed (sched, | ||
683 | TIMEOUT, | ||
684 | &end_badly, "from connect topology (timeout)"); | ||
685 | |||
686 | ok = 0; | ||
687 | } | ||
688 | } | ||
689 | |||
690 | static void | ||
691 | create_topology () | ||
692 | { | ||
693 | peers_left = num_peers; /* Reset counter */ | ||
694 | if (GNUNET_TESTING_create_topology (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) | ||
695 | { | ||
696 | #if VERBOSE | ||
697 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
698 | "Topology set up, now starting peers!\n"); | ||
699 | #endif | ||
700 | GNUNET_TESTING_daemons_continue_startup(pg); | ||
701 | } | ||
702 | else | ||
703 | { | ||
704 | GNUNET_SCHEDULER_cancel (sched, die_task); | ||
705 | die_task = GNUNET_SCHEDULER_add_now (sched, | ||
706 | &end_badly, "from create topology (bad return)"); | ||
707 | } | ||
708 | GNUNET_SCHEDULER_cancel (sched, die_task); | ||
709 | die_task = GNUNET_SCHEDULER_add_delayed (sched, | ||
710 | TIMEOUT, | ||
711 | &end_badly, "from continue startup (timeout)"); | ||
712 | } | ||
713 | |||
714 | /** | ||
715 | * Callback indicating that the hostkey was created for a peer. | ||
716 | * | ||
717 | * @param cls NULL | ||
718 | * @param id the peer identity | ||
719 | * @param d the daemon handle (pretty useless at this point, remove?) | ||
720 | * @param emsg non-null on failure | ||
721 | */ | ||
722 | void hostkey_callback (void *cls, | ||
723 | const struct GNUNET_PeerIdentity *id, | ||
724 | struct GNUNET_TESTING_Daemon *d, | ||
725 | const char *emsg) | ||
726 | { | ||
727 | if (emsg != NULL) | ||
728 | { | ||
729 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Hostkey callback received error: %s\n", emsg); | ||
730 | } | ||
731 | |||
732 | #if VERBOSE > 1 | ||
733 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
734 | "Hostkey (%d/%d) created for peer `%s'\n", | ||
735 | num_peers - peers_left, num_peers, GNUNET_i2s(id)); | ||
736 | #endif | ||
737 | |||
738 | |||
739 | peers_left--; | ||
740 | if (peers_left == 0) | ||
741 | { | ||
742 | #if VERBOSE | ||
743 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
744 | "All %d hostkeys created, now creating topology!\n", | ||
745 | num_peers); | ||
746 | #endif | ||
747 | GNUNET_SCHEDULER_cancel (sched, die_task); | ||
748 | /* Set up task in case topology creation doesn't finish | ||
749 | * within a reasonable amount of time */ | ||
750 | die_task = GNUNET_SCHEDULER_add_delayed (sched, | ||
751 | TIMEOUT, | ||
752 | &end_badly, "from create_topology"); | ||
753 | GNUNET_SCHEDULER_add_now(sched, &create_topology, NULL); | ||
754 | ok = 0; | ||
755 | } | ||
756 | } | ||
757 | |||
758 | |||
759 | static void | ||
760 | run (void *cls, | ||
761 | struct GNUNET_SCHEDULER_Handle *s, | ||
762 | char *const *args, | ||
763 | const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
764 | { | ||
765 | char * topology_str; | ||
766 | char * connect_topology_str; | ||
767 | char * blacklist_topology_str; | ||
768 | char * connect_topology_option_str; | ||
769 | char * connect_topology_option_modifier_string; | ||
770 | sched = s; | ||
771 | |||
772 | /* Get path from configuration file */ | ||
773 | if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string(cfg, "paths", "servicehome", &test_directory)) | ||
774 | { | ||
775 | ok = 404; | ||
776 | return; | ||
777 | } | ||
778 | |||
779 | if ((GNUNET_YES == | ||
780 | GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "topology", | ||
781 | &topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&topology, topology_str))) | ||
782 | { | ||
783 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
784 | "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "TOPOLOGY"); | ||
785 | topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ | ||
786 | } | ||
787 | |||
788 | if ((GNUNET_YES == | ||
789 | GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "connect_topology", | ||
790 | &connect_topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&connection_topology, connect_topology_str))) | ||
791 | { | ||
792 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
793 | "Invalid connect topology `%s' given for section %s option %s\n", connect_topology_str, "TESTING", "CONNECT_TOPOLOGY"); | ||
794 | } | ||
795 | GNUNET_free_non_null(connect_topology_str); | ||
796 | if ((GNUNET_YES == | ||
797 | GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "connect_topology_option", | ||
798 | &connect_topology_option_str)) && (GNUNET_NO == GNUNET_TESTING_topology_option_get(&connect_topology_option, connect_topology_option_str))) | ||
799 | { | ||
800 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
801 | "Invalid connect topology option `%s' given for section %s option %s\n", connect_topology_option_str, "TESTING", "CONNECT_TOPOLOGY_OPTION"); | ||
802 | connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ | ||
803 | } | ||
804 | GNUNET_free_non_null(connect_topology_option_str); | ||
805 | if (GNUNET_YES == | ||
806 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology_option_modifier", | ||
807 | &connect_topology_option_modifier_string)) | ||
808 | { | ||
809 | if (sscanf(connect_topology_option_modifier_string, "%lf", &connect_topology_option_modifier) != 1) | ||
810 | { | ||
811 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
812 | _("Invalid value `%s' for option `%s' in section `%s': expected float\n"), | ||
813 | connect_topology_option_modifier_string, | ||
814 | "connect_topology_option_modifier", | ||
815 | "TESTING"); | ||
816 | } | ||
817 | GNUNET_free (connect_topology_option_modifier_string); | ||
818 | } | ||
819 | |||
820 | if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "blacklist_transports", | ||
821 | &blacklist_transports)) | ||
822 | blacklist_transports = NULL; | ||
823 | |||
824 | if ((GNUNET_YES == | ||
825 | GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "blacklist_topology", | ||
826 | &blacklist_topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&blacklist_topology, blacklist_topology_str))) | ||
827 | { | ||
828 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
829 | "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "BLACKLIST_TOPOLOGY"); | ||
830 | } | ||
831 | GNUNET_free_non_null(topology_str); | ||
832 | GNUNET_free_non_null(blacklist_topology_str); | ||
833 | |||
834 | /* Get number of peers to start from configuration */ | ||
835 | if (GNUNET_SYSERR == | ||
836 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", | ||
837 | &num_peers)) | ||
838 | num_peers = DEFAULT_NUM_PEERS; | ||
839 | |||
840 | if (GNUNET_SYSERR == | ||
841 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "num_puts", | ||
842 | &num_puts)) | ||
843 | num_puts = DEFAULT_NUM_PEERS; | ||
844 | |||
845 | if (GNUNET_SYSERR == | ||
846 | GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "num_gets", | ||
847 | &num_gets)) | ||
848 | num_gets = DEFAULT_NUM_PEERS; | ||
849 | |||
850 | /* Set peers_left so we know when all peers started */ | ||
851 | peers_left = num_peers; | ||
852 | |||
853 | /* Set up a task to end testing if peer start fails */ | ||
854 | die_task = GNUNET_SCHEDULER_add_delayed (sched, | ||
855 | GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, SECONDS_PER_PEER_START * num_peers), | ||
856 | &end_badly, "didn't generate all hostkeys within a reasonable amount of time!!!"); | ||
857 | |||
858 | pg = GNUNET_TESTING_daemons_start (sched, cfg, | ||
859 | peers_left, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, SECONDS_PER_PEER_START * num_peers), &hostkey_callback, NULL, &peers_started_callback, NULL, | ||
860 | &topology_callback, NULL, NULL); | ||
861 | |||
862 | } | ||
863 | |||
864 | static int | ||
865 | check () | ||
866 | { | ||
867 | int ret; | ||
868 | /* Arguments for GNUNET_PROGRAM_run */ | ||
869 | char *const argv[] = {"test-dht-multipeer", /* Name to give running binary */ | ||
870 | "-c", | ||
871 | "test_dht_multipeer_data.conf", /* Config file to use */ | ||
872 | #if VERBOSE | ||
873 | "-L", "DEBUG", | ||
874 | #endif | ||
875 | NULL | ||
876 | }; | ||
877 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
878 | GNUNET_GETOPT_OPTION_END | ||
879 | }; | ||
880 | /* Run the run function as a new program */ | ||
881 | ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, | ||
882 | argv, "test-dht-multipeer", "nohelp", | ||
883 | options, &run, &ok); | ||
884 | if (ret != GNUNET_OK) | ||
885 | { | ||
886 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "`test-dht-multipeer': Failed with error code %d\n", ret); | ||
887 | } | ||
888 | return ok; | ||
889 | } | ||
890 | |||
891 | int | ||
892 | main (int argc, char *argv[]) | ||
893 | { | ||
894 | int ret; | ||
895 | |||
896 | GNUNET_log_setup ("test-dht-multipeer", | ||
897 | #if VERBOSE | ||
898 | "DEBUG", | ||
899 | #else | ||
900 | "WARNING", | ||
901 | #endif | ||
902 | NULL); | ||
903 | ret = check (); | ||
904 | /** | ||
905 | * Need to remove base directory, subdirectories taken care | ||
906 | * of by the testing framework. | ||
907 | */ | ||
908 | if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) | ||
909 | { | ||
910 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory); | ||
911 | } | ||
912 | return ret; | ||
913 | } | ||
914 | |||
915 | /* end of test_dht_twopeer_put_get.c */ | ||
diff --git a/src/dht/test_dht_multipeer_data.conf b/src/dht/test_dht_multipeer_data.conf new file mode 100644 index 000000000..303d2f60d --- /dev/null +++ b/src/dht/test_dht_multipeer_data.conf | |||
@@ -0,0 +1,87 @@ | |||
1 | [fs] | ||
2 | ACCEPT_FROM6 = ::1; | ||
3 | ACCEPT_FROM = 127.0.0.1; | ||
4 | BINARY = gnunet-service-fs | ||
5 | CONFIG = $DEFAULTCONFIG | ||
6 | HOME = $SERVICEHOME | ||
7 | HOSTNAME = localhost | ||
8 | PORT = 2094 | ||
9 | INDEXDB = $SERVICEHOME/idxinfo.lst | ||
10 | |||
11 | [dht] | ||
12 | DEBUG = YES | ||
13 | STOP_ON_CLOSEST = YES | ||
14 | AUTOSTART = YES | ||
15 | ACCEPT_FROM6 = ::1; | ||
16 | ACCEPT_FROM = 127.0.0.1; | ||
17 | BINARY = gnunet-service-dht-new | ||
18 | #PREFIX = xterm -T dht -e gdb --args | ||
19 | #PREFIX = valgrind --log-file=dht_%p | ||
20 | CONFIG = $DEFAULTCONFIG | ||
21 | HOME = $SERVICEHOME | ||
22 | HOSTNAME = localhost | ||
23 | PORT = 2100 | ||
24 | |||
25 | |||
26 | [dhtcache] | ||
27 | QUOTA = 1000000 | ||
28 | DATABASE = sqlite | ||
29 | |||
30 | [transport] | ||
31 | PLUGINS = tcp | ||
32 | DEBUG = NO | ||
33 | ACCEPT_FROM6 = ::1; | ||
34 | ACCEPT_FROM = 127.0.0.1; | ||
35 | NEIGHBOUR_LIMIT = 50 | ||
36 | BINARY = gnunet-service-transport | ||
37 | CONFIG = $DEFAULTCONFIG | ||
38 | HOME = $SERVICEHOME | ||
39 | HOSTNAME = localhost | ||
40 | PORT = 12365 | ||
41 | |||
42 | [core] | ||
43 | TOTAL_QUOTA_OUT = 3932160 | ||
44 | TOTAL_QUOTA_IN = 3932160 | ||
45 | ACCEPT_FROM6 = ::1; | ||
46 | ACCEPT_FROM = 127.0.0.1; | ||
47 | BINARY = gnunet-service-core | ||
48 | CONFIG = $DEFAULTCONFIG | ||
49 | HOME = $SERVICEHOME | ||
50 | HOSTNAME = localhost | ||
51 | PORT = 12092 | ||
52 | |||
53 | [arm] | ||
54 | DEFAULTSERVICES = core dht | ||
55 | ACCEPT_FROM6 = ::1; | ||
56 | ACCEPT_FROM = 127.0.0.1; | ||
57 | BINARY = gnunet-service-arm | ||
58 | CONFIG = $DEFAULTCONFIG | ||
59 | HOME = $SERVICEHOME | ||
60 | HOSTNAME = localhost | ||
61 | PORT = 12366 | ||
62 | DEBUG = YES | ||
63 | |||
64 | [transport-tcp] | ||
65 | TIMEOUT = 300000 | ||
66 | PORT = 12368 | ||
67 | |||
68 | [DHT_TESTING] | ||
69 | MYSQL_LOGGING_EXTENDED = NO | ||
70 | NUM_GETS = 10 | ||
71 | NUM_PUTS = 10 | ||
72 | |||
73 | [TESTING] | ||
74 | CONNECT_TOPOLOGY = CLIQUE | ||
75 | CONNECT_TOPOLOGY_OPTION = CONNECT_RANDOM_SUBSET | ||
76 | CONNECT_TOPOLOGY_OPTION_MODIFIER = 2 | ||
77 | #LOGNMODIFIER = .65 | ||
78 | #PERCENTAGE = .75 | ||
79 | WEAKRANDOM = YES | ||
80 | NUM_PEERS = 5 | ||
81 | |||
82 | [gnunetd] | ||
83 | HOSTKEY = $SERVICEHOME/.hostkey | ||
84 | |||
85 | [PATHS] | ||
86 | DEFAULTCONFIG = test_dht_multipeer_data.conf | ||
87 | SERVICEHOME = /tmp/test-dht-multipeer/ | ||
diff --git a/src/dht/test_dht_twopeer_data.conf b/src/dht/test_dht_twopeer_data.conf index e551cb611..a4e8be65e 100644 --- a/src/dht/test_dht_twopeer_data.conf +++ b/src/dht/test_dht_twopeer_data.conf | |||
@@ -9,15 +9,19 @@ PORT = 2094 | |||
9 | INDEXDB = $SERVICEHOME/idxinfo.lst | 9 | INDEXDB = $SERVICEHOME/idxinfo.lst |
10 | 10 | ||
11 | [dht] | 11 | [dht] |
12 | DEBUG = NO | 12 | DEBUG = YES |
13 | AUTOSTART = YES | 13 | AUTOSTART = YES |
14 | ACCEPT_FROM6 = ::1; | 14 | ACCEPT_FROM6 = ::1; |
15 | ACCEPT_FROM = 127.0.0.1; | 15 | ACCEPT_FROM = 127.0.0.1; |
16 | BINARY = gnunet-service-dht | 16 | BINARY = gnunet-service-dht |
17 | #BINARY = gnunet-service-dht-new | ||
18 | #BINARY = /home/mrwiggles/documents/research/gnunet/gnunet-ng/src/dht/.libs/gnunet-service-dht-new | ||
19 | #PREFIX = xterm -T dht -e gdb --args | ||
17 | CONFIG = $DEFAULTCONFIG | 20 | CONFIG = $DEFAULTCONFIG |
18 | HOME = $SERVICEHOME | 21 | HOME = $SERVICEHOME |
19 | HOSTNAME = localhost | 22 | HOSTNAME = localhost |
20 | PORT = 2100 | 23 | PORT = 2100 |
24 | DISABLE_SOCKET_FORWARDING = YES | ||
21 | 25 | ||
22 | [dhtcache] | 26 | [dhtcache] |
23 | QUOTA = 1000000 | 27 | QUOTA = 1000000 |