diff options
Diffstat (limited to 'src/ats/ats_api_scheduling.c')
-rw-r--r-- | src/ats/ats_api_scheduling.c | 801 |
1 files changed, 0 insertions, 801 deletions
diff --git a/src/ats/ats_api_scheduling.c b/src/ats/ats_api_scheduling.c deleted file mode 100644 index ea4b27653..000000000 --- a/src/ats/ats_api_scheduling.c +++ /dev/null | |||
@@ -1,801 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010-2015 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your 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 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file ats/ats_api_scheduling.c | ||
22 | * @brief automatic transport selection and outbound bandwidth determination | ||
23 | * @author Christian Grothoff | ||
24 | * @author Matthias Wachs | ||
25 | * | ||
26 | * TODO: | ||
27 | * - we could avoid a linear scan over the | ||
28 | * active addresses in some cases, so if | ||
29 | * there is need, we can still optimize here | ||
30 | * - we might want to split off the logic to | ||
31 | * determine LAN vs. WAN, as it has nothing | ||
32 | * to do with accessing the ATS service. | ||
33 | */ | ||
34 | #include "platform.h" | ||
35 | #include "gnunet_ats_service.h" | ||
36 | #include "ats.h" | ||
37 | |||
38 | /** | ||
39 | * How frequently do we scan the interfaces for changes to the addresses? | ||
40 | */ | ||
41 | #define INTERFACE_PROCESSING_INTERVAL GNUNET_TIME_relative_multiply ( \ | ||
42 | GNUNET_TIME_UNIT_MINUTES, 2) | ||
43 | |||
44 | #define LOG(kind, ...) GNUNET_log_from (kind, "ats-scheduling-api", __VA_ARGS__) | ||
45 | |||
46 | /** | ||
47 | * Session ID we use if there is no session / slot. | ||
48 | */ | ||
49 | #define NOT_FOUND 0 | ||
50 | |||
51 | |||
52 | /** | ||
53 | * Information we track per address, incoming or outgoing. It also | ||
54 | * doesn't matter if we have a session, any address that ATS is | ||
55 | * allowed to suggest right now should be tracked. | ||
56 | */ | ||
57 | struct GNUNET_ATS_AddressRecord | ||
58 | { | ||
59 | /** | ||
60 | * Scheduling handle this address record belongs to. | ||
61 | */ | ||
62 | struct GNUNET_ATS_SchedulingHandle *sh; | ||
63 | |||
64 | /** | ||
65 | * Address data. | ||
66 | */ | ||
67 | struct GNUNET_HELLO_Address *address; | ||
68 | |||
69 | /** | ||
70 | * Session handle. NULL if we have an address but no | ||
71 | * active session for this address. | ||
72 | */ | ||
73 | struct GNUNET_ATS_Session *session; | ||
74 | |||
75 | /** | ||
76 | * Performance data about the address. | ||
77 | */ | ||
78 | struct GNUNET_ATS_PropertiesNBO properties; | ||
79 | |||
80 | /** | ||
81 | * Which slot (index) in the session array does | ||
82 | * this record correspond to? | ||
83 | * FIXME: a linear search on this is really crappy! | ||
84 | * Maybe switch to a 64-bit global counter and be | ||
85 | * done with it? Or does that then cause too much | ||
86 | * trouble on the ATS-service side? | ||
87 | */ | ||
88 | uint32_t slot; | ||
89 | |||
90 | /** | ||
91 | * We're about to destroy this address record, just ATS does | ||
92 | * not know this yet. Once ATS confirms its destruction, | ||
93 | * we can clean up. | ||
94 | */ | ||
95 | int in_destroy; | ||
96 | }; | ||
97 | |||
98 | |||
99 | /** | ||
100 | * Handle to the ATS subsystem for bandwidth/transport scheduling information. | ||
101 | */ | ||
102 | struct GNUNET_ATS_SchedulingHandle | ||
103 | { | ||
104 | /** | ||
105 | * Our configuration. | ||
106 | */ | ||
107 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
108 | |||
109 | /** | ||
110 | * Callback to invoke on suggestions. | ||
111 | */ | ||
112 | GNUNET_ATS_AddressSuggestionCallback suggest_cb; | ||
113 | |||
114 | /** | ||
115 | * Closure for @e suggest_cb. | ||
116 | */ | ||
117 | void *suggest_cb_cls; | ||
118 | |||
119 | /** | ||
120 | * Message queue for sending requests to the ATS service. | ||
121 | */ | ||
122 | struct GNUNET_MQ_Handle *mq; | ||
123 | |||
124 | /** | ||
125 | * Array of session objects (we need to translate them to numbers and back | ||
126 | * for the protocol; the offset in the array is the session number on the | ||
127 | * network). Index 0 is always NULL and reserved to represent the NULL pointer. | ||
128 | * Unused entries are also NULL. | ||
129 | */ | ||
130 | struct GNUNET_ATS_AddressRecord **session_array; | ||
131 | |||
132 | /** | ||
133 | * Task to trigger reconnect. | ||
134 | */ | ||
135 | struct GNUNET_SCHEDULER_Task *task; | ||
136 | |||
137 | /** | ||
138 | * Reconnect backoff delay. | ||
139 | */ | ||
140 | struct GNUNET_TIME_Relative backoff; | ||
141 | |||
142 | /** | ||
143 | * Size of the @e session_array. | ||
144 | */ | ||
145 | unsigned int session_array_size; | ||
146 | }; | ||
147 | |||
148 | |||
149 | /** | ||
150 | * Re-establish the connection to the ATS service. | ||
151 | * | ||
152 | * @param sh handle to use to re-connect. | ||
153 | */ | ||
154 | static void | ||
155 | reconnect (struct GNUNET_ATS_SchedulingHandle *sh); | ||
156 | |||
157 | |||
158 | /** | ||
159 | * Re-establish the connection to the ATS service. | ||
160 | * | ||
161 | * @param cls handle to use to re-connect. | ||
162 | */ | ||
163 | static void | ||
164 | reconnect_task (void *cls) | ||
165 | { | ||
166 | struct GNUNET_ATS_SchedulingHandle *sh = cls; | ||
167 | |||
168 | sh->task = NULL; | ||
169 | reconnect (sh); | ||
170 | } | ||
171 | |||
172 | |||
173 | /** | ||
174 | * Disconnect from ATS and then reconnect. | ||
175 | * | ||
176 | * @param sh our handle | ||
177 | */ | ||
178 | static void | ||
179 | force_reconnect (struct GNUNET_ATS_SchedulingHandle *sh) | ||
180 | { | ||
181 | if (NULL != sh->mq) | ||
182 | { | ||
183 | GNUNET_MQ_destroy (sh->mq); | ||
184 | sh->mq = NULL; | ||
185 | } | ||
186 | sh->suggest_cb (sh->suggest_cb_cls, | ||
187 | NULL, NULL, NULL, | ||
188 | GNUNET_BANDWIDTH_ZERO, | ||
189 | GNUNET_BANDWIDTH_ZERO); | ||
190 | sh->backoff = GNUNET_TIME_STD_BACKOFF (sh->backoff); | ||
191 | sh->task = GNUNET_SCHEDULER_add_delayed (sh->backoff, | ||
192 | &reconnect_task, | ||
193 | sh); | ||
194 | } | ||
195 | |||
196 | |||
197 | /** | ||
198 | * Find the session object corresponding to the given session ID. | ||
199 | * | ||
200 | * @param sh our handle | ||
201 | * @param session_id current session ID | ||
202 | * @param peer peer the session belongs to | ||
203 | * @return the session object (or NULL) | ||
204 | */ | ||
205 | static struct GNUNET_ATS_AddressRecord * | ||
206 | find_session (struct GNUNET_ATS_SchedulingHandle *sh, | ||
207 | uint32_t session_id, | ||
208 | const struct GNUNET_PeerIdentity *peer) | ||
209 | { | ||
210 | struct GNUNET_ATS_AddressRecord *ar; | ||
211 | |||
212 | if (session_id >= sh->session_array_size) | ||
213 | { | ||
214 | GNUNET_break (0); | ||
215 | return NULL; | ||
216 | } | ||
217 | if (0 == session_id) | ||
218 | return NULL; | ||
219 | ar = sh->session_array[session_id]; | ||
220 | if (NULL == ar) | ||
221 | { | ||
222 | GNUNET_break (0); | ||
223 | return NULL; | ||
224 | } | ||
225 | if (NULL == ar->address) | ||
226 | { | ||
227 | /* address was destroyed in the meantime, this can happen | ||
228 | as we communicate asynchronously with the ATS service. */ | ||
229 | return NULL; | ||
230 | } | ||
231 | if (0 != GNUNET_memcmp (peer, | ||
232 | &ar->address->peer)) | ||
233 | { | ||
234 | GNUNET_break (0); | ||
235 | return NULL; | ||
236 | } | ||
237 | return ar; | ||
238 | } | ||
239 | |||
240 | |||
241 | /** | ||
242 | * Get an available session ID. | ||
243 | * | ||
244 | * @param sh our handle | ||
245 | * @return an unused slot, but never NOT_FOUND (0) | ||
246 | */ | ||
247 | static uint32_t | ||
248 | find_empty_session_slot (struct GNUNET_ATS_SchedulingHandle *sh) | ||
249 | { | ||
250 | static uint32_t off; | ||
251 | uint32_t i; | ||
252 | |||
253 | GNUNET_assert (0 != sh->session_array_size); | ||
254 | i = 0; | ||
255 | while (((NOT_FOUND == off) || | ||
256 | (NULL != sh->session_array[off % sh->session_array_size])) && | ||
257 | (i < sh->session_array_size)) | ||
258 | { | ||
259 | off++; | ||
260 | i++; | ||
261 | } | ||
262 | if ((NOT_FOUND != off % sh->session_array_size) && | ||
263 | (NULL == sh->session_array[off % sh->session_array_size])) | ||
264 | return off; | ||
265 | i = sh->session_array_size; | ||
266 | GNUNET_array_grow (sh->session_array, | ||
267 | sh->session_array_size, | ||
268 | sh->session_array_size * 2); | ||
269 | return i; | ||
270 | } | ||
271 | |||
272 | |||
273 | /** | ||
274 | * Get the ID for the given session object. | ||
275 | * | ||
276 | * @param sh our handle | ||
277 | * @param session session object | ||
278 | * @param address the address we are looking for | ||
279 | * @return the session id or NOT_FOUND for error | ||
280 | */ | ||
281 | static uint32_t | ||
282 | find_session_id (struct GNUNET_ATS_SchedulingHandle *sh, | ||
283 | struct GNUNET_ATS_Session *session, | ||
284 | const struct GNUNET_HELLO_Address *address) | ||
285 | { | ||
286 | uint32_t i; | ||
287 | |||
288 | if (NULL == address) | ||
289 | { | ||
290 | GNUNET_break (0); | ||
291 | return NOT_FOUND; | ||
292 | } | ||
293 | for (i = 1; i < sh->session_array_size; i++) | ||
294 | if ((NULL != sh->session_array[i]) && | ||
295 | (GNUNET_NO == sh->session_array[i]->in_destroy) && | ||
296 | ((session == sh->session_array[i]->session) || | ||
297 | (NULL == sh->session_array[i]->session)) && | ||
298 | (0 == GNUNET_memcmp (&address->peer, | ||
299 | &sh->session_array[i]->address->peer)) && | ||
300 | (0 == GNUNET_HELLO_address_cmp (address, | ||
301 | sh->session_array[i]->address))) | ||
302 | return i; | ||
303 | return NOT_FOUND; | ||
304 | } | ||
305 | |||
306 | |||
307 | /** | ||
308 | * Release the session slot from the session table (ATS service is | ||
309 | * also done using it). | ||
310 | * | ||
311 | * @param sh our handle | ||
312 | * @param session_id identifies session that is no longer valid | ||
313 | */ | ||
314 | static void | ||
315 | release_session (struct GNUNET_ATS_SchedulingHandle *sh, | ||
316 | uint32_t session_id) | ||
317 | { | ||
318 | struct GNUNET_ATS_AddressRecord *ar; | ||
319 | |||
320 | if (NOT_FOUND == session_id) | ||
321 | return; | ||
322 | if (session_id >= sh->session_array_size) | ||
323 | { | ||
324 | GNUNET_break (0); | ||
325 | force_reconnect (sh); | ||
326 | return; | ||
327 | } | ||
328 | /* this slot should have been removed from remove_session before */ | ||
329 | ar = sh->session_array[session_id]; | ||
330 | if (NULL != ar->session) | ||
331 | { | ||
332 | GNUNET_break (0); | ||
333 | force_reconnect (sh); | ||
334 | return; | ||
335 | } | ||
336 | GNUNET_HELLO_address_free (ar->address); | ||
337 | GNUNET_free (ar); | ||
338 | sh->session_array[session_id] = NULL; | ||
339 | } | ||
340 | |||
341 | |||
342 | /** | ||
343 | * Type of a function to call when we receive a session release | ||
344 | * message from the service. | ||
345 | * | ||
346 | * @param cls the `struct GNUNET_ATS_SchedulingHandle` | ||
347 | * @param srm message received | ||
348 | */ | ||
349 | static void | ||
350 | handle_ats_session_release (void *cls, | ||
351 | const struct GNUNET_ATS_SessionReleaseMessage *srm) | ||
352 | { | ||
353 | struct GNUNET_ATS_SchedulingHandle *sh = cls; | ||
354 | |||
355 | /* Note: peer field in srm not necessary right now, | ||
356 | but might be good to have in the future */ | ||
357 | release_session (sh, | ||
358 | ntohl (srm->session_id)); | ||
359 | } | ||
360 | |||
361 | |||
362 | /** | ||
363 | * Type of a function to call when we receive a address suggestion | ||
364 | * message from the service. | ||
365 | * | ||
366 | * @param cls the `struct GNUNET_ATS_SchedulingHandle` | ||
367 | * @param m message received | ||
368 | */ | ||
369 | static void | ||
370 | handle_ats_address_suggestion (void *cls, | ||
371 | const struct AddressSuggestionMessage *m) | ||
372 | { | ||
373 | struct GNUNET_ATS_SchedulingHandle *sh = cls; | ||
374 | struct GNUNET_ATS_AddressRecord *ar; | ||
375 | uint32_t session_id; | ||
376 | |||
377 | session_id = ntohl (m->session_id); | ||
378 | if (0 == session_id) | ||
379 | { | ||
380 | GNUNET_break (0); | ||
381 | force_reconnect (sh); | ||
382 | return; | ||
383 | } | ||
384 | ar = find_session (sh, | ||
385 | session_id, | ||
386 | &m->peer); | ||
387 | if (NULL == ar) | ||
388 | { | ||
389 | GNUNET_break (0); | ||
390 | force_reconnect (sh); | ||
391 | return; | ||
392 | } | ||
393 | if (NULL == sh->suggest_cb) | ||
394 | return; | ||
395 | if (GNUNET_YES == ar->in_destroy) | ||
396 | { | ||
397 | /* ignore suggestion, as this address is dying, unless BW is 0, | ||
398 | in that case signal 'disconnect' via BW 0 */ | ||
399 | if ((0 == ntohl (m->bandwidth_out.value__)) && | ||
400 | (0 == ntohl (m->bandwidth_in.value__))) | ||
401 | { | ||
402 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
403 | "ATS suggests disconnect from peer `%s' with BW %u/%u\n", | ||
404 | GNUNET_i2s (&ar->address->peer), | ||
405 | (unsigned int) ntohl (m->bandwidth_out.value__), | ||
406 | (unsigned int) ntohl (m->bandwidth_in.value__)); | ||
407 | sh->suggest_cb (sh->suggest_cb_cls, | ||
408 | &m->peer, | ||
409 | NULL, | ||
410 | NULL, | ||
411 | m->bandwidth_out, | ||
412 | m->bandwidth_in); | ||
413 | } | ||
414 | return; | ||
415 | } | ||
416 | if ((NULL == ar->session) && | ||
417 | (GNUNET_HELLO_address_check_option (ar->address, | ||
418 | GNUNET_HELLO_ADDRESS_INFO_INBOUND))) | ||
419 | { | ||
420 | GNUNET_break (0); | ||
421 | return; | ||
422 | } | ||
423 | sh->backoff = GNUNET_TIME_UNIT_ZERO; | ||
424 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
425 | "ATS suggests address slot %u for peer `%s' using plugin %s\n", | ||
426 | ar->slot, | ||
427 | GNUNET_i2s (&ar->address->peer), | ||
428 | ar->address->transport_name); | ||
429 | sh->suggest_cb (sh->suggest_cb_cls, | ||
430 | &m->peer, | ||
431 | ar->address, | ||
432 | ar->session, | ||
433 | m->bandwidth_out, | ||
434 | m->bandwidth_in); | ||
435 | } | ||
436 | |||
437 | |||
438 | /** | ||
439 | * We encountered an error handling the MQ to the | ||
440 | * ATS service. Reconnect. | ||
441 | * | ||
442 | * @param cls the `struct GNUNET_ATS_SchedulingHandle` | ||
443 | * @param error details about the error | ||
444 | */ | ||
445 | static void | ||
446 | error_handler (void *cls, | ||
447 | enum GNUNET_MQ_Error error) | ||
448 | { | ||
449 | struct GNUNET_ATS_SchedulingHandle *sh = cls; | ||
450 | |||
451 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
452 | "ATS connection died (code %d), reconnecting\n", | ||
453 | (int) error); | ||
454 | force_reconnect (sh); | ||
455 | } | ||
456 | |||
457 | |||
458 | /** | ||
459 | * Generate and transmit the `struct AddressAddMessage` for the given | ||
460 | * address record. | ||
461 | * | ||
462 | * @param sh the scheduling handle to use for transmission | ||
463 | * @param ar the address to inform the ATS service about | ||
464 | */ | ||
465 | static void | ||
466 | send_add_address_message (struct GNUNET_ATS_SchedulingHandle *sh, | ||
467 | const struct GNUNET_ATS_AddressRecord *ar) | ||
468 | { | ||
469 | struct GNUNET_MQ_Envelope *ev; | ||
470 | struct AddressAddMessage *m; | ||
471 | char *pm; | ||
472 | size_t namelen; | ||
473 | size_t msize; | ||
474 | |||
475 | if (NULL == sh->mq) | ||
476 | return; /* disconnected, skip for now */ | ||
477 | GNUNET_break (GNUNET_NT_UNSPECIFIED != ar->properties.scope); | ||
478 | namelen = strlen (ar->address->transport_name) + 1; | ||
479 | msize = ar->address->address_length + namelen; | ||
480 | ev = GNUNET_MQ_msg_extra (m, msize, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_ADD); | ||
481 | m->peer = ar->address->peer; | ||
482 | m->address_length = htons (ar->address->address_length); | ||
483 | m->address_local_info = htonl ((uint32_t) ar->address->local_info); | ||
484 | m->plugin_name_length = htons (namelen); | ||
485 | m->session_id = htonl (ar->slot); | ||
486 | m->properties = ar->properties; | ||
487 | |||
488 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
489 | "Adding address for peer `%s', plugin `%s', session %p slot %u\n", | ||
490 | GNUNET_i2s (&ar->address->peer), | ||
491 | ar->address->transport_name, | ||
492 | ar->session, | ||
493 | ar->slot); | ||
494 | pm = (char *) &m[1]; | ||
495 | GNUNET_memcpy (pm, | ||
496 | ar->address->address, | ||
497 | ar->address->address_length); | ||
498 | if (NULL != ar->address->transport_name) | ||
499 | GNUNET_memcpy (&pm[ar->address->address_length], | ||
500 | ar->address->transport_name, | ||
501 | namelen); | ||
502 | GNUNET_MQ_send (sh->mq, ev); | ||
503 | } | ||
504 | |||
505 | |||
506 | /** | ||
507 | * Re-establish the connection to the ATS service. | ||
508 | * | ||
509 | * @param sh handle to use to re-connect. | ||
510 | */ | ||
511 | static void | ||
512 | reconnect (struct GNUNET_ATS_SchedulingHandle *sh) | ||
513 | { | ||
514 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
515 | GNUNET_MQ_hd_fixed_size (ats_session_release, | ||
516 | GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE, | ||
517 | struct GNUNET_ATS_SessionReleaseMessage, | ||
518 | sh), | ||
519 | GNUNET_MQ_hd_fixed_size (ats_address_suggestion, | ||
520 | GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION, | ||
521 | struct AddressSuggestionMessage, | ||
522 | sh), | ||
523 | GNUNET_MQ_handler_end () | ||
524 | }; | ||
525 | struct GNUNET_MQ_Envelope *ev; | ||
526 | struct ClientStartMessage *init; | ||
527 | unsigned int i; | ||
528 | struct GNUNET_ATS_AddressRecord *ar; | ||
529 | |||
530 | GNUNET_assert (NULL == sh->mq); | ||
531 | sh->mq = GNUNET_CLIENT_connect (sh->cfg, | ||
532 | "ats", | ||
533 | handlers, | ||
534 | &error_handler, | ||
535 | sh); | ||
536 | if (NULL == sh->mq) | ||
537 | { | ||
538 | GNUNET_break (0); | ||
539 | force_reconnect (sh); | ||
540 | return; | ||
541 | } | ||
542 | ev = GNUNET_MQ_msg (init, | ||
543 | GNUNET_MESSAGE_TYPE_ATS_START); | ||
544 | init->start_flag = htonl (START_FLAG_SCHEDULING); | ||
545 | GNUNET_MQ_send (sh->mq, ev); | ||
546 | if (NULL == sh->mq) | ||
547 | return; | ||
548 | for (i = 0; i < sh->session_array_size; i++) | ||
549 | { | ||
550 | ar = sh->session_array[i]; | ||
551 | if (NULL == ar) | ||
552 | continue; | ||
553 | send_add_address_message (sh, ar); | ||
554 | if (NULL == sh->mq) | ||
555 | return; | ||
556 | } | ||
557 | } | ||
558 | |||
559 | |||
560 | /** | ||
561 | * Initialize the ATS subsystem. | ||
562 | * | ||
563 | * @param cfg configuration to use | ||
564 | * @param suggest_cb notification to call whenever the suggestation changed | ||
565 | * @param suggest_cb_cls closure for @a suggest_cb | ||
566 | * @return ats context | ||
567 | */ | ||
568 | struct GNUNET_ATS_SchedulingHandle * | ||
569 | GNUNET_ATS_scheduling_init (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
570 | GNUNET_ATS_AddressSuggestionCallback suggest_cb, | ||
571 | void *suggest_cb_cls) | ||
572 | { | ||
573 | struct GNUNET_ATS_SchedulingHandle *sh; | ||
574 | |||
575 | sh = GNUNET_new (struct GNUNET_ATS_SchedulingHandle); | ||
576 | sh->cfg = cfg; | ||
577 | sh->suggest_cb = suggest_cb; | ||
578 | sh->suggest_cb_cls = suggest_cb_cls; | ||
579 | GNUNET_array_grow (sh->session_array, | ||
580 | sh->session_array_size, | ||
581 | 4); | ||
582 | reconnect (sh); | ||
583 | return sh; | ||
584 | } | ||
585 | |||
586 | |||
587 | /** | ||
588 | * Client is done with ATS scheduling, release resources. | ||
589 | * | ||
590 | * @param sh handle to release | ||
591 | */ | ||
592 | void | ||
593 | GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh) | ||
594 | { | ||
595 | struct GNUNET_ATS_AddressRecord *ar; | ||
596 | unsigned int i; | ||
597 | |||
598 | if (NULL != sh->mq) | ||
599 | { | ||
600 | GNUNET_MQ_destroy (sh->mq); | ||
601 | sh->mq = NULL; | ||
602 | } | ||
603 | if (NULL != sh->task) | ||
604 | { | ||
605 | GNUNET_SCHEDULER_cancel (sh->task); | ||
606 | sh->task = NULL; | ||
607 | } | ||
608 | for (i = 0; i < sh->session_array_size; i++) | ||
609 | { | ||
610 | if (NULL != (ar = sh->session_array[i])) | ||
611 | { | ||
612 | GNUNET_HELLO_address_free (ar->address); | ||
613 | GNUNET_free (ar); | ||
614 | sh->session_array[i] = NULL; | ||
615 | } | ||
616 | } | ||
617 | GNUNET_array_grow (sh->session_array, | ||
618 | sh->session_array_size, | ||
619 | 0); | ||
620 | GNUNET_free (sh); | ||
621 | } | ||
622 | |||
623 | |||
624 | /** | ||
625 | * We have a new address ATS should know. Addresses have to be added | ||
626 | * with this function before they can be: updated, set in use and | ||
627 | * destroyed. | ||
628 | * | ||
629 | * @param sh handle | ||
630 | * @param address the address | ||
631 | * @param session session handle, can be NULL | ||
632 | * @param prop performance data for the address | ||
633 | * @return handle to the address representation inside ATS, NULL | ||
634 | * on error (i.e. ATS knows this exact address already) | ||
635 | */ | ||
636 | struct GNUNET_ATS_AddressRecord * | ||
637 | GNUNET_ATS_address_add (struct GNUNET_ATS_SchedulingHandle *sh, | ||
638 | const struct GNUNET_HELLO_Address *address, | ||
639 | struct GNUNET_ATS_Session *session, | ||
640 | const struct GNUNET_ATS_Properties *prop) | ||
641 | { | ||
642 | struct GNUNET_ATS_AddressRecord *ar; | ||
643 | size_t namelen; | ||
644 | size_t msize; | ||
645 | uint32_t s; | ||
646 | |||
647 | if (NULL == address) | ||
648 | { | ||
649 | /* we need a valid address */ | ||
650 | GNUNET_break (0); | ||
651 | return NULL; | ||
652 | } | ||
653 | GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope); | ||
654 | namelen = strlen (address->transport_name) + 1; | ||
655 | msize = address->address_length + namelen; | ||
656 | if ((msize + sizeof(struct AddressUpdateMessage) >= | ||
657 | GNUNET_MAX_MESSAGE_SIZE) || | ||
658 | (address->address_length >= GNUNET_MAX_MESSAGE_SIZE) || | ||
659 | (namelen >= GNUNET_MAX_MESSAGE_SIZE)) | ||
660 | { | ||
661 | /* address too large for us, this should not happen */ | ||
662 | GNUNET_break (0); | ||
663 | return NULL; | ||
664 | } | ||
665 | |||
666 | if (NOT_FOUND != | ||
667 | find_session_id (sh, | ||
668 | session, | ||
669 | address)) | ||
670 | { | ||
671 | /* Already existing, nothing todo, but this should not happen */ | ||
672 | GNUNET_break (0); | ||
673 | return NULL; | ||
674 | } | ||
675 | s = find_empty_session_slot (sh); | ||
676 | ar = GNUNET_new (struct GNUNET_ATS_AddressRecord); | ||
677 | ar->sh = sh; | ||
678 | ar->slot = s; | ||
679 | ar->session = session; | ||
680 | ar->address = GNUNET_HELLO_address_copy (address); | ||
681 | GNUNET_ATS_properties_hton (&ar->properties, | ||
682 | prop); | ||
683 | sh->session_array[s] = ar; | ||
684 | send_add_address_message (sh, ar); | ||
685 | return ar; | ||
686 | } | ||
687 | |||
688 | |||
689 | /** | ||
690 | * An address was used to initiate a session. | ||
691 | * | ||
692 | * @param ar address record to update information for | ||
693 | * @param session session handle | ||
694 | */ | ||
695 | void | ||
696 | GNUNET_ATS_address_add_session (struct GNUNET_ATS_AddressRecord *ar, | ||
697 | struct GNUNET_ATS_Session *session) | ||
698 | { | ||
699 | GNUNET_break (NULL == ar->session); | ||
700 | ar->session = session; | ||
701 | } | ||
702 | |||
703 | |||
704 | /** | ||
705 | * A session was destroyed, disassociate it from the | ||
706 | * given address record. If this was an incoming | ||
707 | * address, destroy the address as well. | ||
708 | * | ||
709 | * @param ar address record to update information for | ||
710 | * @param session session handle | ||
711 | * @return #GNUNET_YES if the @a ar was destroyed because | ||
712 | * it was an incoming address, | ||
713 | * #GNUNET_NO if the @ar was kept because we can | ||
714 | * use it still to establish a new session | ||
715 | */ | ||
716 | int | ||
717 | GNUNET_ATS_address_del_session (struct GNUNET_ATS_AddressRecord *ar, | ||
718 | struct GNUNET_ATS_Session *session) | ||
719 | { | ||
720 | GNUNET_assert (session == ar->session); | ||
721 | ar->session = NULL; | ||
722 | if (GNUNET_HELLO_address_check_option (ar->address, | ||
723 | GNUNET_HELLO_ADDRESS_INFO_INBOUND)) | ||
724 | { | ||
725 | GNUNET_ATS_address_destroy (ar); | ||
726 | return GNUNET_YES; | ||
727 | } | ||
728 | return GNUNET_NO; | ||
729 | } | ||
730 | |||
731 | |||
732 | /** | ||
733 | * We have updated performance statistics for a given address. Note | ||
734 | * that this function can be called for addresses that are currently | ||
735 | * in use as well as addresses that are valid but not actively in use. | ||
736 | * Furthermore, the peer may not even be connected to us right now (in | ||
737 | * which case the call may be ignored or the information may be stored | ||
738 | * for later use). Update bandwidth assignments. | ||
739 | * | ||
740 | * @param ar address record to update information for | ||
741 | * @param prop performance data for the address | ||
742 | */ | ||
743 | void | ||
744 | GNUNET_ATS_address_update (struct GNUNET_ATS_AddressRecord *ar, | ||
745 | const struct GNUNET_ATS_Properties *prop) | ||
746 | { | ||
747 | struct GNUNET_ATS_SchedulingHandle *sh = ar->sh; | ||
748 | struct GNUNET_MQ_Envelope *ev; | ||
749 | struct AddressUpdateMessage *m; | ||
750 | |||
751 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
752 | "Updating address for peer `%s', plugin `%s', session %p slot %u\n", | ||
753 | GNUNET_i2s (&ar->address->peer), | ||
754 | ar->address->transport_name, | ||
755 | ar->session, | ||
756 | ar->slot); | ||
757 | GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope); | ||
758 | GNUNET_ATS_properties_hton (&ar->properties, | ||
759 | prop); | ||
760 | if (NULL == sh->mq) | ||
761 | return; /* disconnected, skip for now */ | ||
762 | ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE); | ||
763 | m->session_id = htonl (ar->slot); | ||
764 | m->peer = ar->address->peer; | ||
765 | m->properties = ar->properties; | ||
766 | GNUNET_MQ_send (sh->mq, | ||
767 | ev); | ||
768 | } | ||
769 | |||
770 | |||
771 | /** | ||
772 | * An address got destroyed, stop using it as a valid address. | ||
773 | * | ||
774 | * @param ar address to destroy | ||
775 | */ | ||
776 | void | ||
777 | GNUNET_ATS_address_destroy (struct GNUNET_ATS_AddressRecord *ar) | ||
778 | { | ||
779 | struct GNUNET_ATS_SchedulingHandle *sh = ar->sh; | ||
780 | struct GNUNET_MQ_Envelope *ev; | ||
781 | struct AddressDestroyedMessage *m; | ||
782 | |||
783 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
784 | "Deleting address for peer `%s', plugin `%s', slot %u session %p\n", | ||
785 | GNUNET_i2s (&ar->address->peer), | ||
786 | ar->address->transport_name, | ||
787 | ar->slot, | ||
788 | ar->session); | ||
789 | GNUNET_break (NULL == ar->session); | ||
790 | ar->session = NULL; | ||
791 | ar->in_destroy = GNUNET_YES; | ||
792 | if (NULL == sh->mq) | ||
793 | return; | ||
794 | ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED); | ||
795 | m->session_id = htonl (ar->slot); | ||
796 | m->peer = ar->address->peer; | ||
797 | GNUNET_MQ_send (sh->mq, ev); | ||
798 | } | ||
799 | |||
800 | |||
801 | /* end of ats_api_scheduling.c */ | ||