diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-08-12 10:54:28 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-08-12 10:54:28 +0000 |
commit | 3d016df6e9f16a224637ae1f525acdcbbce9fbed (patch) | |
tree | c198a1c8a918412d018f446d98ee553a3a1dac68 /src/ats | |
parent | 180f2e637029d045e3c72dc3e13fddb1f9f30141 (diff) | |
download | gnunet-3d016df6e9f16a224637ae1f525acdcbbce9fbed.tar.gz gnunet-3d016df6e9f16a224637ae1f525acdcbbce9fbed.zip |
initial ATS service refactoring
Diffstat (limited to 'src/ats')
-rw-r--r-- | src/ats/Makefile.am | 38 | ||||
-rw-r--r-- | src/ats/ats_api.c | 793 |
2 files changed, 831 insertions, 0 deletions
diff --git a/src/ats/Makefile.am b/src/ats/Makefile.am new file mode 100644 index 000000000..39aa3f87b --- /dev/null +++ b/src/ats/Makefile.am | |||
@@ -0,0 +1,38 @@ | |||
1 | INCLUDES = -I$(top_srcdir)/src/include | ||
2 | |||
3 | if MINGW | ||
4 | WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols | ||
5 | endif | ||
6 | |||
7 | if USE_COVERAGE | ||
8 | AM_CFLAGS = -fprofile-arcs -ftest-coverage | ||
9 | endif | ||
10 | |||
11 | lib_LTLIBRARIES = libgnunetats.la | ||
12 | |||
13 | libgnunetats_la_SOURCES = \ | ||
14 | ats_api.c | ||
15 | |||
16 | |||
17 | #bin_PROGRAMS = \ | ||
18 | # gnunet-service-ats | ||
19 | |||
20 | #gnunet_service_ats_SOURCES = \ | ||
21 | # gnunet-service-ats.c | ||
22 | #gnunet_service_ats_LDADD = \ | ||
23 | # $(top_builddir)/src/util/libgnunetutil.la \ | ||
24 | # $(GN_LIBINTL) | ||
25 | |||
26 | |||
27 | #check_PROGRAMS = \ | ||
28 | # test_ats_api | ||
29 | |||
30 | #if ENABLE_TEST_RUN | ||
31 | #TESTS = $(check_PROGRAMS) | ||
32 | #endif | ||
33 | |||
34 | #test_ats_api_SOURCES = \ | ||
35 | # test_ats_api.c | ||
36 | #test_ats_api_LDADD = \ | ||
37 | # $(top_builddir)/src/util/libgnunetutil.la | ||
38 | |||
diff --git a/src/ats/ats_api.c b/src/ats/ats_api.c new file mode 100644 index 000000000..8609ac5a5 --- /dev/null +++ b/src/ats/ats_api.c | |||
@@ -0,0 +1,793 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2010,2011 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 ats/ats_api.c | ||
22 | * @brief automatic transport selection API | ||
23 | * @author Christian Grothoff | ||
24 | * @author Matthias Wachs | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_ats_service.h" | ||
28 | |||
29 | // NOTE: this implementation is simply supposed | ||
30 | // to implement a simplistic strategy in-process; | ||
31 | // in the future, we plan to replace it with a real | ||
32 | // service implementation | ||
33 | |||
34 | /** | ||
35 | * Allocation record for a peer's address. | ||
36 | */ | ||
37 | struct AllocationRecord | ||
38 | { | ||
39 | |||
40 | /** | ||
41 | * Public key of the peer. | ||
42 | */ | ||
43 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; | ||
44 | |||
45 | /** | ||
46 | * Performance information associated with this address (array). | ||
47 | */ | ||
48 | struct GNUNET_TRANSPORT_ATS_Information *ats; | ||
49 | |||
50 | /** | ||
51 | * Name of the plugin | ||
52 | */ | ||
53 | char *plugin_name; | ||
54 | |||
55 | /** | ||
56 | * Address this record represents, allocated at the end of this struct. | ||
57 | */ | ||
58 | const void *plugin_addr; | ||
59 | |||
60 | /** | ||
61 | * Session associated with this record. | ||
62 | */ | ||
63 | struct Session *session; | ||
64 | |||
65 | /** | ||
66 | * Number of bytes in plugin_addr. | ||
67 | */ | ||
68 | size_t plugin_addr_len; | ||
69 | |||
70 | /** | ||
71 | * Number of entries in 'ats'. | ||
72 | */ | ||
73 | uint32_t ats_count; | ||
74 | |||
75 | /** | ||
76 | * Bandwidth assigned to this address right now, 0 for none. | ||
77 | */ | ||
78 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth; | ||
79 | |||
80 | /** | ||
81 | * Set to GNUNET_YES if this is the connected address of a connected peer. | ||
82 | */ | ||
83 | int connected; | ||
84 | |||
85 | }; | ||
86 | |||
87 | |||
88 | /** | ||
89 | * Opaque handle to stop incremental validation address callbacks. | ||
90 | */ | ||
91 | struct GNUNET_ATS_SuggestionContext | ||
92 | { | ||
93 | |||
94 | /** | ||
95 | * Function to call with our final suggestion. | ||
96 | */ | ||
97 | GNUNET_ATS_AddressSuggestionCallback cb; | ||
98 | |||
99 | /** | ||
100 | * Closure for 'cb'. | ||
101 | */ | ||
102 | void *cb_cls; | ||
103 | |||
104 | /** | ||
105 | * Global ATS handle. | ||
106 | */ | ||
107 | struct GNUNET_ATS_Handle *atc; | ||
108 | |||
109 | /** | ||
110 | * Which peer are we monitoring? | ||
111 | */ | ||
112 | struct GNUNET_PeerIdentity target; | ||
113 | |||
114 | }; | ||
115 | |||
116 | |||
117 | /** | ||
118 | * Handle to the ATS subsystem. | ||
119 | */ | ||
120 | struct GNUNET_ATS_Handle | ||
121 | { | ||
122 | /** | ||
123 | * Configuration. | ||
124 | */ | ||
125 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
126 | |||
127 | /** | ||
128 | * Function to call when the allocation changes. | ||
129 | */ | ||
130 | GNUNET_TRANSPORT_ATS_AllocationNotification alloc_cb; | ||
131 | |||
132 | /** | ||
133 | * Closure for 'alloc_cb'. | ||
134 | */ | ||
135 | void *alloc_cb_cls; | ||
136 | |||
137 | /** | ||
138 | * Information about all connected peers. Maps peer identities | ||
139 | * to one or more 'struct AllocationRecord' values. | ||
140 | */ | ||
141 | struct GNUNET_CONTAINER_MultiHashMap *peers; | ||
142 | |||
143 | /** | ||
144 | * Map of PeerIdentities to 'struct GNUNET_ATS_SuggestionContext's. | ||
145 | */ | ||
146 | struct GNUNET_CONTAINER_MultiHashMap *notify_map; | ||
147 | |||
148 | |||
149 | /** | ||
150 | * Task scheduled to update our bandwidth assignment. | ||
151 | */ | ||
152 | GNUNET_SCHEDULER_TaskIdentifier ba_task; | ||
153 | |||
154 | /** | ||
155 | * Total bandwidth per configuration. | ||
156 | */ | ||
157 | unsigned long long total_bps; | ||
158 | }; | ||
159 | |||
160 | |||
161 | /** | ||
162 | * Count number of connected records. | ||
163 | * | ||
164 | * @param cls pointer to counter | ||
165 | * @param key identity of the peer associated with the records | ||
166 | * @param value a 'struct AllocationRecord' | ||
167 | * @return GNUNET_YES (continue iteration) | ||
168 | */ | ||
169 | static int | ||
170 | count_connections (void *cls, | ||
171 | const GNUNET_HashCode *key, | ||
172 | void *value) | ||
173 | { | ||
174 | unsigned int *ac = cls; | ||
175 | struct AllocationRecord *ar = value; | ||
176 | |||
177 | if (GNUNET_YES == ar->connected) | ||
178 | (*ac)++; | ||
179 | return GNUNET_YES; | ||
180 | } | ||
181 | |||
182 | struct SetBandwidthContext | ||
183 | { | ||
184 | struct GNUNET_ATS_Handle *atc; | ||
185 | struct GNUNET_BANDWIDTH_Value32NBO bw; | ||
186 | }; | ||
187 | |||
188 | /** | ||
189 | * Set bandwidth based on record. | ||
190 | * | ||
191 | * @param cls 'struct SetBandwidthContext' | ||
192 | * @param key identity of the peer associated with the records | ||
193 | * @param value a 'struct AllocationRecord' | ||
194 | * @return GNUNET_YES (continue iteration) | ||
195 | */ | ||
196 | static int | ||
197 | set_bw_connections (void *cls, | ||
198 | const GNUNET_HashCode *key, | ||
199 | void *value) | ||
200 | { | ||
201 | struct SetBandwidthContext *sbc = cls; | ||
202 | struct AllocationRecord *ar = value; | ||
203 | |||
204 | if (GNUNET_YES == ar->connected) | ||
205 | { | ||
206 | ar->bandwidth = sbc->bw; | ||
207 | sbc->atc->alloc_cb (sbc->atc->alloc_cb_cls, | ||
208 | (const struct GNUNET_PeerIdentity*) key, | ||
209 | ar->plugin_name, | ||
210 | ar->session, | ||
211 | ar->plugin_addr, | ||
212 | ar->plugin_addr_len, | ||
213 | ar->bandwidth); | ||
214 | } | ||
215 | else if (ntohl(ar->bandwidth.value__) > 0) | ||
216 | { | ||
217 | ar->bandwidth = GNUNET_BANDWIDTH_value_init (0); | ||
218 | sbc->atc->alloc_cb (sbc->atc->alloc_cb_cls, | ||
219 | (const struct GNUNET_PeerIdentity*) key, | ||
220 | ar->plugin_name, | ||
221 | ar->session, | ||
222 | ar->plugin_addr, | ||
223 | ar->plugin_addr_len, | ||
224 | ar->bandwidth); | ||
225 | } | ||
226 | return GNUNET_YES; | ||
227 | } | ||
228 | |||
229 | |||
230 | /** | ||
231 | * Task run to update bandwidth assignments. | ||
232 | * | ||
233 | * @param cls the 'struct GNUNET_ATS_Handle' | ||
234 | * @param tc scheduler context | ||
235 | */ | ||
236 | static void | ||
237 | update_bandwidth_task (void *cls, | ||
238 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
239 | { | ||
240 | struct GNUNET_ATS_Handle *atc = cls; | ||
241 | unsigned int ac; | ||
242 | struct SetBandwidthContext bwc; | ||
243 | |||
244 | atc->ba_task = GNUNET_SCHEDULER_NO_TASK; | ||
245 | /* FIXME: update calculations NICELY; what follows is a naive version */ | ||
246 | GNUNET_CONTAINER_multihashmap_iterate (atc->peers, | ||
247 | &count_connections, | ||
248 | &ac); | ||
249 | bwc.atc = atc; | ||
250 | bwc.bw = GNUNET_BANDWIDTH_value_init (atc->total_bps / ac); | ||
251 | GNUNET_CONTAINER_multihashmap_iterate (atc->peers, | ||
252 | &set_bw_connections, | ||
253 | &bwc); | ||
254 | } | ||
255 | |||
256 | |||
257 | /** | ||
258 | * Calculate an updated bandwidth assignment and notify. | ||
259 | * | ||
260 | * @param ats handle | ||
261 | * @param change which allocation record changed? | ||
262 | */ | ||
263 | static void | ||
264 | update_bandwidth_assignment (struct GNUNET_ATS_Handle *atc, | ||
265 | struct AllocationRecord *change) | ||
266 | { | ||
267 | /* FIXME: based on the 'change', update the LP-problem... */ | ||
268 | if (atc->ba_task == GNUNET_SCHEDULER_NO_TASK) | ||
269 | atc->ba_task = GNUNET_SCHEDULER_add_now (&update_bandwidth_task, | ||
270 | atc); | ||
271 | } | ||
272 | |||
273 | |||
274 | /** | ||
275 | * Function called with feasbile addresses we might want to suggest. | ||
276 | * | ||
277 | * @param cls the 'struct GNUNET_ATS_SuggestionContext' | ||
278 | * @param key identity of the peer | ||
279 | * @param value a 'struct AllocationRecord' for the peer | ||
280 | * @return GNUNET_NO if we're done, GNUNET_YES if we did not suggest an address yet | ||
281 | */ | ||
282 | static int | ||
283 | suggest_address (void *cls, | ||
284 | const GNUNET_HashCode *key, | ||
285 | void *value) | ||
286 | { | ||
287 | struct GNUNET_ATS_SuggestionContest *asc = cls; | ||
288 | struct AllocationRecord *ar = value; | ||
289 | |||
290 | // FIXME... | ||
291 | return GNUNET_YES; | ||
292 | } | ||
293 | |||
294 | |||
295 | /** | ||
296 | * We would like to establish a new connection with a peer. | ||
297 | * ATS should suggest a good address to begin with. | ||
298 | * | ||
299 | * @param atc handle | ||
300 | * @param peer identity of the new peer | ||
301 | * @param cb function to call with the address | ||
302 | * @param cb_cls closure for cb | ||
303 | */ | ||
304 | struct GNUNET_ATS_SuggestionContext * | ||
305 | GNUNET_ATS_suggest_address (struct GNUNET_ATS_Handle *atc, | ||
306 | const struct GNUNET_PeerIdentity *peer, | ||
307 | GNUNET_ATS_AddressSuggestionCallback cb, | ||
308 | void *cb_cls) | ||
309 | { | ||
310 | struct GNUNET_ATS_SuggestionContext *asc; | ||
311 | |||
312 | asc = GNUNET_malloc (sizeof (struct GNUNET_ATS_SuggestionContext)); | ||
313 | asc->cb = cb; | ||
314 | asc->cb_cls = cb_cls; | ||
315 | asc->atc = atc; | ||
316 | asc->target = *peer; | ||
317 | GNUNET_CONTAINER_multihashmap_get_multiple (atc->peers, | ||
318 | &peer->hashPubKey, | ||
319 | &suggest_address, | ||
320 | asc); | ||
321 | if (NULL == asc->cb) | ||
322 | { | ||
323 | GNUNET_free (asc); | ||
324 | return NULL; | ||
325 | } | ||
326 | GNUNET_CONTAINER_multihashmap_put (atc->notify_map, | ||
327 | &peer->hashPubKey, | ||
328 | asc, | ||
329 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
330 | return asc; | ||
331 | } | ||
332 | |||
333 | |||
334 | /** | ||
335 | * Cancel suggestion request. | ||
336 | * | ||
337 | * @param asc handle of the request to cancel | ||
338 | */ | ||
339 | void | ||
340 | GNUNET_ATS_suggest_address_cancel (struct GNUNET_ATS_SuggestionContext *asc) | ||
341 | { | ||
342 | GNUNET_assert (GNUNET_OK == | ||
343 | GNUNET_CONTAINER_multihashmap_remove (asc->atc->notify_map, | ||
344 | &asc->target.hashPubKey, | ||
345 | asc)); | ||
346 | GNUNET_free (asc); | ||
347 | } | ||
348 | |||
349 | |||
350 | /** | ||
351 | * Initialize the ATS subsystem. | ||
352 | * | ||
353 | * @param cfg configuration to use | ||
354 | * @param alloc_cb notification to call whenever the allocation changed | ||
355 | * @param alloc_cb_cls closure for 'alloc_cb' | ||
356 | * @return ats context | ||
357 | */ | ||
358 | struct GNUNET_ATS_Handle * | ||
359 | GNUNET_ATS_init (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
360 | GNUNET_TRANSPORT_ATS_AllocationNotification alloc_cb, | ||
361 | void *alloc_cb_cls) | ||
362 | { | ||
363 | struct GNUNET_ATS_Handle *atc; | ||
364 | |||
365 | atc = GNUNET_malloc (sizeof (struct GNUNET_ATS_Handle)); | ||
366 | atc->cfg = cfg; | ||
367 | atc->alloc_cb = alloc_cb; | ||
368 | atc->alloc_cb_cls = alloc_cb_cls; | ||
369 | atc->peers = GNUNET_CONTAINER_multihashmap_create (256); | ||
370 | GNUNET_CONFIGURATION_get_value_number (cfg, | ||
371 | "core", | ||
372 | "TOTAL_QUOTA_OUT", | ||
373 | &atc->total_bps); | ||
374 | return atc; | ||
375 | } | ||
376 | |||
377 | |||
378 | /** | ||
379 | * Free an allocation record. | ||
380 | * | ||
381 | * @param cls unused | ||
382 | * @param key identity of the peer associated with the record | ||
383 | * @param value the 'struct AllocationRecord' to free | ||
384 | * @return GNUNET_OK (continue to iterate) | ||
385 | */ | ||
386 | static int | ||
387 | destroy_allocation_record (void *cls, | ||
388 | const GNUNET_HashCode *key, | ||
389 | void *value) | ||
390 | { | ||
391 | struct AllocationRecord *ar = value; | ||
392 | |||
393 | GNUNET_array_grow (ar->ats, ar->ats_count, 0); | ||
394 | GNUNET_free (ar->plugin_name); | ||
395 | GNUNET_free (ar); | ||
396 | return GNUNET_OK; | ||
397 | } | ||
398 | |||
399 | |||
400 | /** | ||
401 | * Shutdown the ATS subsystem. | ||
402 | * | ||
403 | * @param atc handle | ||
404 | */ | ||
405 | void | ||
406 | GNUNET_ATS_shutdown (struct GNUNET_ATS_Handle *atc) | ||
407 | { | ||
408 | if (GNUNET_SCHEDULER_NO_TASK != atc->ba_task) | ||
409 | { | ||
410 | GNUNET_SCHEDULER_cancel (atc->ba_task); | ||
411 | atc->ba_task = GNUNET_SCHEDULER_NO_TASK; | ||
412 | } | ||
413 | GNUNET_CONTAINER_multihashmap_iterate (atc->peers, | ||
414 | &destroy_allocation_record, | ||
415 | NULL); | ||
416 | GNUNET_CONTAINER_multihashmap_destroy (atc->peers); | ||
417 | GNUNET_assert (GNUNET_CONTAINER_multihashmap_size (atc->notify_map) == 0); | ||
418 | GNUNET_CONTAINER_multihashmap_destroy (atc->notify_map); | ||
419 | atc->notify_map = NULL; | ||
420 | GNUNET_free (atc); | ||
421 | } | ||
422 | |||
423 | |||
424 | /** | ||
425 | * Closure for 'update_session' | ||
426 | */ | ||
427 | struct UpdateSessionContext | ||
428 | { | ||
429 | /** | ||
430 | * Ats handle. | ||
431 | */ | ||
432 | struct GNUNET_ATS_Handle *atc; | ||
433 | |||
434 | /** | ||
435 | * Allocation record with new information. | ||
436 | */ | ||
437 | struct AllocationRecord *arnew; | ||
438 | }; | ||
439 | |||
440 | |||
441 | /** | ||
442 | * Update an allocation record, merging with the new information | ||
443 | * | ||
444 | * @param cls a new 'struct AllocationRecord' | ||
445 | * @param key identity of the peer associated with the records | ||
446 | * @param value the old 'struct AllocationRecord' | ||
447 | * @return GNUNET_YES if the records do not match, | ||
448 | * GNUNET_NO if the record do match and 'old' was updated | ||
449 | */ | ||
450 | static int | ||
451 | update_session (void *cls, | ||
452 | const GNUNET_HashCode *key, | ||
453 | void *value) | ||
454 | { | ||
455 | struct UpdateSessionContext *usc = cls; | ||
456 | struct AllocationRecord *arnew = usc->arnew; | ||
457 | struct AllocationRecord *arold = value; | ||
458 | int change; | ||
459 | |||
460 | if (0 != strcmp (arnew->plugin_name, arold->plugin_name)) | ||
461 | return GNUNET_YES; | ||
462 | if ( (arnew->session == arold->session) || | ||
463 | ( (arold->session == NULL) && | ||
464 | (arold->plugin_addr_len == arnew->plugin_addr_len) && | ||
465 | (0 == memcmp (arold->plugin_addr, | ||
466 | arnew->plugin_addr, | ||
467 | arnew->plugin_addr_len)) ) ) | ||
468 | { | ||
469 | change = GNUNET_NO; | ||
470 | /* records match */ | ||
471 | if (arnew->session != arold->session) | ||
472 | { | ||
473 | arold->session = arnew->session; | ||
474 | change = GNUNET_YES; | ||
475 | } | ||
476 | if ( (arnew->connected == GNUNET_YES) && | ||
477 | (arold->connected == GNUNET_NO) ) | ||
478 | { | ||
479 | arold->connected = GNUNET_YES; | ||
480 | change = GNUNET_YES; | ||
481 | } | ||
482 | // FIXME: merge ats arrays of (arold, arnew); | ||
483 | |||
484 | if (GNUNET_YES == change) | ||
485 | update_bandwidth_assignment (usc->atc, arold); | ||
486 | return GNUNET_NO; | ||
487 | } | ||
488 | return GNUNET_YES; | ||
489 | } | ||
490 | |||
491 | |||
492 | /** | ||
493 | * Create an allocation record with the given properties. | ||
494 | * | ||
495 | * @param plugin_name name of the currently used transport plugin | ||
496 | * @param session session in use (if available) | ||
497 | * @param plugin_addr address in use (if available) | ||
498 | * @param plugin_addr_len number of bytes in plugin_addr | ||
499 | * @param ats performance data for the connection | ||
500 | * @param ats_count number of performance records in 'ats' | ||
501 | */ | ||
502 | static struct AllocationRecord * | ||
503 | create_allocation_record (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, | ||
504 | const char *plugin_name, | ||
505 | struct Session *session, | ||
506 | const void *plugin_addr, | ||
507 | size_t plugin_addr_len, | ||
508 | const struct GNUNET_TRANSPORT_ATS_Information *ats, | ||
509 | uint32_t ats_count) | ||
510 | { | ||
511 | struct AllocationRecord *ar; | ||
512 | |||
513 | ar = GNUNET_malloc (sizeof (struct AllocationRecord) + plugin_addr_len); | ||
514 | ar->public_key = *public_key; | ||
515 | ar->plugin_name = GNUNET_strdup (plugin_name); | ||
516 | ar->plugin_addr = &ar[1]; | ||
517 | memcpy (&ar[1], plugin_addr, plugin_addr_len); | ||
518 | ar->session = session; | ||
519 | ar->plugin_addr_len = plugin_addr_len; | ||
520 | GNUNET_array_grow (ar->ats, | ||
521 | ar->ats_count, | ||
522 | ats_count); | ||
523 | memcpy (ar->ats, | ||
524 | ats, | ||
525 | ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)); | ||
526 | return ar; | ||
527 | } | ||
528 | |||
529 | |||
530 | /** | ||
531 | * Mark all matching allocation records as not connected. | ||
532 | * | ||
533 | * @param cls 'struct GTS_AtsHandle' | ||
534 | * @param key identity of the peer associated with the record | ||
535 | * @param value the 'struct AllocationRecord' to clear the 'connected' flag | ||
536 | * @return GNUNET_OK (continue to iterate) | ||
537 | */ | ||
538 | static int | ||
539 | disconnect_peer (void *cls, | ||
540 | const GNUNET_HashCode *key, | ||
541 | void *value) | ||
542 | { | ||
543 | struct GNUNET_ATS_Handle *atc = cls; | ||
544 | struct AllocationRecord *ar = value; | ||
545 | |||
546 | if (GNUNET_YES == ar->connected) | ||
547 | { | ||
548 | ar->connected = GNUNET_NO; | ||
549 | update_bandwidth_assignment (atc, ar); | ||
550 | } | ||
551 | return GNUNET_OK; | ||
552 | } | ||
553 | |||
554 | |||
555 | /** | ||
556 | * We established a new connection with a peer (for example, because | ||
557 | * core asked for it or because the other peer connected to us). | ||
558 | * Calculate bandwidth assignments including the new peer. | ||
559 | * | ||
560 | * @param atc handle | ||
561 | * @param public_key public key of the peer | ||
562 | * @param peer identity of the new peer | ||
563 | * @param plugin_name name of the currently used transport plugin | ||
564 | * @param session session in use (if available) | ||
565 | * @param plugin_addr address in use (if available) | ||
566 | * @param plugin_addr_len number of bytes in plugin_addr | ||
567 | * @param ats performance data for the connection | ||
568 | * @param ats_count number of performance records in 'ats' | ||
569 | */ | ||
570 | void | ||
571 | GNUNET_ATS_peer_connect (struct GNUNET_ATS_Handle *atc, | ||
572 | const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, | ||
573 | const struct GNUNET_PeerIdentity *peer, | ||
574 | const char *plugin_name, | ||
575 | struct Session *session, | ||
576 | const void *plugin_addr, | ||
577 | size_t plugin_addr_len, | ||
578 | const struct GNUNET_TRANSPORT_ATS_Information *ats, | ||
579 | uint32_t ats_count) | ||
580 | { | ||
581 | struct AllocationRecord *ar; | ||
582 | struct UpdateSessionContext usc; | ||
583 | |||
584 | (void) GNUNET_CONTAINER_multihashmap_iterate (atc->peers, | ||
585 | &disconnect_peer, | ||
586 | atc); | ||
587 | ar = create_allocation_record (public_key, | ||
588 | plugin_name, | ||
589 | session, | ||
590 | plugin_addr, | ||
591 | plugin_addr_len, | ||
592 | ats, | ||
593 | ats_count); | ||
594 | ar->connected = GNUNET_YES; | ||
595 | usc.atc = atc; | ||
596 | usc.arnew = ar; | ||
597 | if (GNUNET_SYSERR == | ||
598 | GNUNET_CONTAINER_multihashmap_iterate (atc->peers, | ||
599 | &update_session, | ||
600 | &usc)) | ||
601 | { | ||
602 | destroy_allocation_record (NULL, &peer->hashPubKey, ar); | ||
603 | return; | ||
604 | } | ||
605 | GNUNET_assert (GNUNET_OK == | ||
606 | GNUNET_CONTAINER_multihashmap_put (atc->peers, | ||
607 | &peer->hashPubKey, | ||
608 | ar, | ||
609 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); | ||
610 | } | ||
611 | |||
612 | |||
613 | /** | ||
614 | * We disconnected from the given peer (for example, because ats, core | ||
615 | * or blacklist asked for it or because the other peer disconnected). | ||
616 | * Calculate bandwidth assignments without the peer. | ||
617 | * | ||
618 | * @param atc handle | ||
619 | * @param peer identity of the new peer | ||
620 | */ | ||
621 | void | ||
622 | GNUNET_ATS_peer_disconnect (struct GNUNET_ATS_Handle *atc, | ||
623 | const struct GNUNET_PeerIdentity *peer) | ||
624 | { | ||
625 | (void) GNUNET_CONTAINER_multihashmap_get_multiple (atc->peers, | ||
626 | &peer->hashPubKey, | ||
627 | &disconnect_peer, | ||
628 | atc); | ||
629 | } | ||
630 | |||
631 | |||
632 | /** | ||
633 | * Closure for 'destroy_allocation_record' | ||
634 | */ | ||
635 | struct SessionDestroyContext | ||
636 | { | ||
637 | /** | ||
638 | * Ats handle. | ||
639 | */ | ||
640 | struct GNUNET_ATS_Handle *atc; | ||
641 | |||
642 | /** | ||
643 | * Session being destroyed. | ||
644 | */ | ||
645 | const struct Session *session; | ||
646 | }; | ||
647 | |||
648 | |||
649 | /** | ||
650 | * Free an allocation record matching the given session. | ||
651 | * | ||
652 | * @param cls the 'struct SessionDestroyContext' | ||
653 | * @param key identity of the peer associated with the record | ||
654 | * @param value the 'struct AllocationRecord' to free | ||
655 | * @return GNUNET_OK (continue to iterate) | ||
656 | */ | ||
657 | static int | ||
658 | destroy_session (void *cls, | ||
659 | const GNUNET_HashCode *key, | ||
660 | void *value) | ||
661 | { | ||
662 | struct SessionDestroyContext *sdc = cls; | ||
663 | struct AllocationRecord *ar = value; | ||
664 | |||
665 | if (ar->session != sdc->session) | ||
666 | return GNUNET_OK; | ||
667 | ar->session = NULL; | ||
668 | if (ar->plugin_addr != NULL) | ||
669 | return GNUNET_OK; | ||
670 | GNUNET_assert (GNUNET_OK == | ||
671 | GNUNET_CONTAINER_multihashmap_remove (sdc->atc->peers, | ||
672 | key, | ||
673 | ar)); | ||
674 | if (GNUNET_YES == ar->connected); | ||
675 | { | ||
676 | /* FIXME: is this supposed to be allowed? What to do then? */ | ||
677 | GNUNET_break (0); | ||
678 | } | ||
679 | destroy_allocation_record (NULL, key, ar); | ||
680 | return GNUNET_OK; | ||
681 | } | ||
682 | |||
683 | |||
684 | /** | ||
685 | * A session got destroyed, stop including it as a valid address. | ||
686 | * | ||
687 | * @param atc handle | ||
688 | * @param peer identity of the peer | ||
689 | * @param session session handle that is no longer valid | ||
690 | */ | ||
691 | void | ||
692 | GNUNET_ATS_session_destroyed (struct GNUNET_ATS_Handle *atc, | ||
693 | const struct GNUNET_PeerIdentity *peer, | ||
694 | const struct Session *session) | ||
695 | { | ||
696 | struct SessionDestroyContext sdc; | ||
697 | |||
698 | sdc.atc = atc; | ||
699 | sdc.session = session; | ||
700 | (void) GNUNET_CONTAINER_multihashmap_iterate (atc->peers, | ||
701 | &destroy_session, | ||
702 | &sdc); | ||
703 | } | ||
704 | |||
705 | |||
706 | /** | ||
707 | * Notify validation watcher that an entry is now valid | ||
708 | * | ||
709 | * @param cls 'struct ValidationEntry' that is now valid | ||
710 | * @param key peer identity (unused) | ||
711 | * @param value a 'GST_ValidationIteratorContext' to notify | ||
712 | * @return GNUNET_YES (continue to iterate) | ||
713 | */ | ||
714 | static int | ||
715 | notify_valid (void *cls, | ||
716 | const GNUNET_HashCode *key, | ||
717 | void *value) | ||
718 | { | ||
719 | struct AllocationRecord *ar = cls; | ||
720 | struct GNUNET_ATS_SuggestionContext *asc = value; | ||
721 | |||
722 | asc->cb (asc->cb_cls, | ||
723 | &ar->public_key, | ||
724 | &asc->target, | ||
725 | ar->plugin_name, | ||
726 | ar->plugin_addr, | ||
727 | ar->plugin_addr_len, | ||
728 | ar->ats, ar->ats_count); | ||
729 | return GNUNET_OK; | ||
730 | } | ||
731 | |||
732 | |||
733 | /** | ||
734 | * We have updated performance statistics for a given address. Note | ||
735 | * that this function can be called for addresses that are currently | ||
736 | * in use as well as addresses that are valid but not actively in use. | ||
737 | * Furthermore, the peer may not even be connected to us right now (in | ||
738 | * which case the call may be ignored or the information may be stored | ||
739 | * for later use). Update bandwidth assignments. | ||
740 | * | ||
741 | * @param atc handle | ||
742 | * @param public_key public key of the peer | ||
743 | * @param peer identity of the peer | ||
744 | * @param plugin_name name of the transport plugin | ||
745 | * @param session session handle (if available) | ||
746 | * @param plugin_addr address (if available) | ||
747 | * @param plugin_addr_len number of bytes in plugin_addr | ||
748 | * @param ats performance data for the address | ||
749 | * @param ats_count number of performance records in 'ats' | ||
750 | */ | ||
751 | void | ||
752 | GNUNET_ATS_address_update (struct GNUNET_ATS_Handle *atc, | ||
753 | const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, | ||
754 | const struct GNUNET_PeerIdentity *peer, | ||
755 | const char *plugin_name, | ||
756 | struct Session *session, | ||
757 | const void *plugin_addr, | ||
758 | size_t plugin_addr_len, | ||
759 | const struct GNUNET_TRANSPORT_ATS_Information *ats, | ||
760 | uint32_t ats_count) | ||
761 | { | ||
762 | struct AllocationRecord *ar; | ||
763 | struct UpdateSessionContext usc; | ||
764 | |||
765 | ar = create_allocation_record (public_key, | ||
766 | plugin_name, | ||
767 | session, | ||
768 | plugin_addr, | ||
769 | plugin_addr_len, | ||
770 | ats, | ||
771 | ats_count); | ||
772 | usc.atc = atc; | ||
773 | usc.arnew = ar; | ||
774 | if (GNUNET_SYSERR == | ||
775 | GNUNET_CONTAINER_multihashmap_iterate (atc->peers, | ||
776 | &update_session, | ||
777 | &usc)) | ||
778 | { | ||
779 | destroy_allocation_record (NULL, &peer->hashPubKey, ar); | ||
780 | return; | ||
781 | } | ||
782 | GNUNET_assert (GNUNET_OK == | ||
783 | GNUNET_CONTAINER_multihashmap_put (atc->peers, | ||
784 | &peer->hashPubKey, | ||
785 | ar, | ||
786 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); | ||
787 | GNUNET_CONTAINER_multihashmap_get_multiple (atc->notify_map, | ||
788 | &peer->hashPubKey, | ||
789 | ¬ify_valid, | ||
790 | ar); | ||
791 | } | ||
792 | |||
793 | /* end of file gnunet-service-transport_ats.c */ | ||