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