diff options
Diffstat (limited to 'src/ats/ats_api_performance.c')
-rw-r--r-- | src/ats/ats_api_performance.c | 996 |
1 files changed, 0 insertions, 996 deletions
diff --git a/src/ats/ats_api_performance.c b/src/ats/ats_api_performance.c deleted file mode 100644 index 7349fb989..000000000 --- a/src/ats/ats_api_performance.c +++ /dev/null | |||
@@ -1,996 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010, 2011, 2016 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_performance.c | ||
22 | * @brief automatic transport selection and outbound bandwidth determination | ||
23 | * @author Christian Grothoff | ||
24 | * @author Matthias Wachs | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_ats_service.h" | ||
28 | #include "ats.h" | ||
29 | |||
30 | |||
31 | #define LOG(kind, ...) GNUNET_log_from (kind, "ats-performance-api", \ | ||
32 | __VA_ARGS__) | ||
33 | |||
34 | |||
35 | /** | ||
36 | * Linked list of pending reservations. | ||
37 | */ | ||
38 | struct GNUNET_ATS_ReservationContext | ||
39 | { | ||
40 | /** | ||
41 | * Kept in a DLL. | ||
42 | */ | ||
43 | struct GNUNET_ATS_ReservationContext *next; | ||
44 | |||
45 | /** | ||
46 | * Kept in a DLL. | ||
47 | */ | ||
48 | struct GNUNET_ATS_ReservationContext *prev; | ||
49 | |||
50 | /** | ||
51 | * Target peer. | ||
52 | */ | ||
53 | struct GNUNET_PeerIdentity peer; | ||
54 | |||
55 | /** | ||
56 | * Desired reservation | ||
57 | */ | ||
58 | int32_t size; | ||
59 | |||
60 | /** | ||
61 | * Function to call on result. | ||
62 | */ | ||
63 | GNUNET_ATS_ReservationCallback rcb; | ||
64 | |||
65 | /** | ||
66 | * Closure for @e rcb | ||
67 | */ | ||
68 | void *rcb_cls; | ||
69 | |||
70 | /** | ||
71 | * Do we need to undo this reservation if it succeeded? Set to | ||
72 | * #GNUNET_YES if a reservation is cancelled. (at that point, 'info' | ||
73 | * is also set to NULL; however, info will ALSO be NULL for the | ||
74 | * reservation context that is created to undo the original request, | ||
75 | * so 'info' being NULL cannot be used to check if undo is | ||
76 | * required). | ||
77 | */ | ||
78 | int undo; | ||
79 | }; | ||
80 | |||
81 | |||
82 | /** | ||
83 | * Linked list of pending reservations. | ||
84 | */ | ||
85 | struct GNUNET_ATS_AddressListHandle | ||
86 | { | ||
87 | /** | ||
88 | * Kept in a DLL. | ||
89 | */ | ||
90 | struct GNUNET_ATS_AddressListHandle *next; | ||
91 | |||
92 | /** | ||
93 | * Kept in a DLL. | ||
94 | */ | ||
95 | struct GNUNET_ATS_AddressListHandle *prev; | ||
96 | |||
97 | /** | ||
98 | * Performance handle | ||
99 | */ | ||
100 | struct GNUNET_ATS_PerformanceHandle *ph; | ||
101 | |||
102 | /** | ||
103 | * Callback | ||
104 | */ | ||
105 | GNUNET_ATS_AddressInformationCallback cb; | ||
106 | |||
107 | /** | ||
108 | * Callback closure for @e cb | ||
109 | */ | ||
110 | void *cb_cls; | ||
111 | |||
112 | /** | ||
113 | * Target peer. | ||
114 | */ | ||
115 | struct GNUNET_PeerIdentity peer; | ||
116 | |||
117 | /** | ||
118 | * Return all or specific peer only | ||
119 | */ | ||
120 | int all_peers; | ||
121 | |||
122 | /** | ||
123 | * Return all or used address only | ||
124 | */ | ||
125 | int all_addresses; | ||
126 | |||
127 | /** | ||
128 | * Request multiplexing | ||
129 | */ | ||
130 | uint32_t id; | ||
131 | }; | ||
132 | |||
133 | |||
134 | /** | ||
135 | * ATS Handle to obtain and/or modify performance information. | ||
136 | */ | ||
137 | struct GNUNET_ATS_PerformanceHandle | ||
138 | { | ||
139 | /** | ||
140 | * Our configuration. | ||
141 | */ | ||
142 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
143 | |||
144 | /** | ||
145 | * Callback to invoke when an address has performance changes. | ||
146 | */ | ||
147 | GNUNET_ATS_AddressInformationCallback addr_info_cb; | ||
148 | |||
149 | /** | ||
150 | * Closure for @e addr_info_cb. | ||
151 | */ | ||
152 | void *addr_info_cb_cls; | ||
153 | |||
154 | /** | ||
155 | * Connection to ATS service. | ||
156 | */ | ||
157 | struct GNUNET_MQ_Handle *mq; | ||
158 | |||
159 | /** | ||
160 | * Head of linked list of pending reservation requests. | ||
161 | */ | ||
162 | struct GNUNET_ATS_ReservationContext *reservation_head; | ||
163 | |||
164 | /** | ||
165 | * Tail of linked list of pending reservation requests. | ||
166 | */ | ||
167 | struct GNUNET_ATS_ReservationContext *reservation_tail; | ||
168 | |||
169 | /** | ||
170 | * Head of linked list of pending address list requests. | ||
171 | */ | ||
172 | struct GNUNET_ATS_AddressListHandle *addresslist_head; | ||
173 | |||
174 | /** | ||
175 | * Tail of linked list of pending address list requests. | ||
176 | */ | ||
177 | struct GNUNET_ATS_AddressListHandle *addresslist_tail; | ||
178 | |||
179 | /** | ||
180 | * Current request for transmission to ATS. | ||
181 | */ | ||
182 | struct GNUNET_CLIENT_TransmitHandle *th; | ||
183 | |||
184 | /** | ||
185 | * Task to trigger reconnect. | ||
186 | */ | ||
187 | struct GNUNET_SCHEDULER_Task *task; | ||
188 | |||
189 | /** | ||
190 | * Reconnect backoff delay. | ||
191 | */ | ||
192 | struct GNUNET_TIME_Relative backoff; | ||
193 | |||
194 | /** | ||
195 | * Monitor request multiplexing | ||
196 | */ | ||
197 | uint32_t monitor_id; | ||
198 | |||
199 | /** | ||
200 | * Request multiplexing | ||
201 | */ | ||
202 | uint32_t id; | ||
203 | |||
204 | /** | ||
205 | * Is the receive loop active? | ||
206 | */ | ||
207 | int in_receive; | ||
208 | }; | ||
209 | |||
210 | /** | ||
211 | * Re-establish the connection to the ATS service. | ||
212 | * | ||
213 | * @param ph handle to use to re-connect. | ||
214 | */ | ||
215 | static void | ||
216 | reconnect (struct GNUNET_ATS_PerformanceHandle *ph); | ||
217 | |||
218 | |||
219 | /** | ||
220 | * Re-establish the connection to the ATS service. | ||
221 | * | ||
222 | * @param cls handle to use to re-connect. | ||
223 | */ | ||
224 | static void | ||
225 | reconnect_task (void *cls) | ||
226 | { | ||
227 | struct GNUNET_ATS_PerformanceHandle *ph = cls; | ||
228 | |||
229 | ph->task = NULL; | ||
230 | reconnect (ph); | ||
231 | } | ||
232 | |||
233 | |||
234 | /** | ||
235 | * Reconnect to the ATS service, something went wrong. | ||
236 | * | ||
237 | * @param ph handle to reconnect | ||
238 | */ | ||
239 | static void | ||
240 | do_reconnect (struct GNUNET_ATS_PerformanceHandle *ph) | ||
241 | { | ||
242 | struct GNUNET_ATS_ReservationContext *rc; | ||
243 | struct GNUNET_ATS_AddressListHandle *alh; | ||
244 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_zero; | ||
245 | |||
246 | if (NULL != ph->mq) | ||
247 | { | ||
248 | GNUNET_MQ_destroy (ph->mq); | ||
249 | ph->mq = NULL; | ||
250 | } | ||
251 | while (NULL != (rc = ph->reservation_head)) | ||
252 | { | ||
253 | GNUNET_CONTAINER_DLL_remove (ph->reservation_head, | ||
254 | ph->reservation_tail, | ||
255 | rc); | ||
256 | if (NULL != rc->rcb) | ||
257 | rc->rcb (rc->rcb_cls, | ||
258 | NULL, | ||
259 | 0, | ||
260 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
261 | GNUNET_free (rc); | ||
262 | } | ||
263 | bandwidth_zero.value__ = htonl (0); | ||
264 | while (NULL != (alh = ph->addresslist_head)) | ||
265 | { | ||
266 | GNUNET_CONTAINER_DLL_remove (ph->addresslist_head, | ||
267 | ph->addresslist_tail, | ||
268 | alh); | ||
269 | if (NULL != alh->cb) | ||
270 | alh->cb (alh->cb_cls, | ||
271 | NULL, | ||
272 | GNUNET_NO, | ||
273 | bandwidth_zero, | ||
274 | bandwidth_zero, | ||
275 | NULL); | ||
276 | GNUNET_free (alh); | ||
277 | } | ||
278 | if (NULL != ph->addr_info_cb) | ||
279 | { | ||
280 | /* Indicate reconnect */ | ||
281 | ph->addr_info_cb (ph->addr_info_cb_cls, | ||
282 | NULL, | ||
283 | GNUNET_NO, | ||
284 | bandwidth_zero, | ||
285 | bandwidth_zero, | ||
286 | NULL); | ||
287 | } | ||
288 | ph->backoff = GNUNET_TIME_STD_BACKOFF (ph->backoff); | ||
289 | ph->task = GNUNET_SCHEDULER_add_delayed (ph->backoff, | ||
290 | &reconnect_task, | ||
291 | ph); | ||
292 | } | ||
293 | |||
294 | |||
295 | /** | ||
296 | * We received a peer information message. Validate and process it. | ||
297 | * | ||
298 | * @param cls our context with the callback | ||
299 | * @param pi the message | ||
300 | * @return #GNUNET_OK if the message was well-formed | ||
301 | */ | ||
302 | static int | ||
303 | check_peer_information (void *cls, | ||
304 | const struct PeerInformationMessage *pi) | ||
305 | { | ||
306 | const char *plugin_address; | ||
307 | const char *plugin_name; | ||
308 | uint16_t plugin_address_length; | ||
309 | uint16_t plugin_name_length; | ||
310 | |||
311 | plugin_address_length = ntohs (pi->address_length); | ||
312 | plugin_name_length = ntohs (pi->plugin_name_length); | ||
313 | plugin_address = (const char *) &pi[1]; | ||
314 | plugin_name = &plugin_address[plugin_address_length]; | ||
315 | if ((plugin_address_length + plugin_name_length | ||
316 | + sizeof(struct PeerInformationMessage) != ntohs (pi->header.size)) || | ||
317 | (plugin_name[plugin_name_length - 1] != '\0')) | ||
318 | { | ||
319 | GNUNET_break (0); | ||
320 | return GNUNET_SYSERR; | ||
321 | } | ||
322 | return GNUNET_OK; | ||
323 | } | ||
324 | |||
325 | |||
326 | /** | ||
327 | * We received a peer information message. Validate and process it. | ||
328 | * | ||
329 | * @param cls our context with the callback | ||
330 | * @param pi the message | ||
331 | * @return #GNUNET_OK if the message was well-formed | ||
332 | */ | ||
333 | static void | ||
334 | handle_peer_information (void *cls, | ||
335 | const struct PeerInformationMessage *pi) | ||
336 | { | ||
337 | struct GNUNET_ATS_PerformanceHandle *ph = cls; | ||
338 | const char *plugin_address; | ||
339 | const char *plugin_name; | ||
340 | struct GNUNET_HELLO_Address address; | ||
341 | uint16_t plugin_address_length; | ||
342 | int addr_active; | ||
343 | struct GNUNET_ATS_Properties prop; | ||
344 | |||
345 | if (NULL == ph->addr_info_cb) | ||
346 | return; | ||
347 | plugin_address_length = ntohs (pi->address_length); | ||
348 | addr_active = (int) ntohl (pi->address_active); | ||
349 | plugin_address = (const char *) &pi[1]; | ||
350 | plugin_name = &plugin_address[plugin_address_length]; | ||
351 | |||
352 | GNUNET_ATS_properties_ntoh (&prop, | ||
353 | &pi->properties); | ||
354 | address.peer = pi->peer; | ||
355 | address.local_info = (enum GNUNET_HELLO_AddressInfo) ntohl ( | ||
356 | pi->address_local_info); | ||
357 | address.address = plugin_address; | ||
358 | address.address_length = plugin_address_length; | ||
359 | address.transport_name = plugin_name; | ||
360 | ph->addr_info_cb (ph->addr_info_cb_cls, | ||
361 | &address, | ||
362 | addr_active, | ||
363 | pi->bandwidth_out, | ||
364 | pi->bandwidth_in, | ||
365 | &prop); | ||
366 | } | ||
367 | |||
368 | |||
369 | /** | ||
370 | * We received a reservation result message. Validate and process it. | ||
371 | * | ||
372 | * @param cls our context with the callback | ||
373 | * @param rr the message | ||
374 | */ | ||
375 | static void | ||
376 | handle_reservation_result (void *cls, | ||
377 | const struct ReservationResultMessage *rr) | ||
378 | { | ||
379 | struct GNUNET_ATS_PerformanceHandle *ph = cls; | ||
380 | struct GNUNET_ATS_ReservationContext *rc; | ||
381 | int32_t amount; | ||
382 | |||
383 | amount = ntohl (rr->amount); | ||
384 | rc = ph->reservation_head; | ||
385 | if (0 != GNUNET_memcmp (&rr->peer, | ||
386 | &rc->peer)) | ||
387 | { | ||
388 | GNUNET_break (0); | ||
389 | reconnect (ph); | ||
390 | return; | ||
391 | } | ||
392 | GNUNET_CONTAINER_DLL_remove (ph->reservation_head, | ||
393 | ph->reservation_tail, | ||
394 | rc); | ||
395 | if ((0 == amount) || | ||
396 | (NULL != rc->rcb)) | ||
397 | { | ||
398 | /* tell client if not cancelled */ | ||
399 | if (NULL != rc->rcb) | ||
400 | rc->rcb (rc->rcb_cls, | ||
401 | &rr->peer, | ||
402 | amount, | ||
403 | GNUNET_TIME_relative_ntoh (rr->res_delay)); | ||
404 | GNUNET_free (rc); | ||
405 | return; | ||
406 | } | ||
407 | /* amount non-zero, but client cancelled, consider undo! */ | ||
408 | if (GNUNET_YES != rc->undo) | ||
409 | { | ||
410 | GNUNET_free (rc); | ||
411 | return; /* do not try to undo failed undos or negative amounts */ | ||
412 | } | ||
413 | GNUNET_free (rc); | ||
414 | (void) GNUNET_ATS_reserve_bandwidth (ph, | ||
415 | &rr->peer, | ||
416 | -amount, | ||
417 | NULL, NULL); | ||
418 | } | ||
419 | |||
420 | |||
421 | /** | ||
422 | * We received a PeerInformationMessage. Validate it. | ||
423 | * | ||
424 | * @param cls our context with the callback | ||
425 | * @param pi the message | ||
426 | * @return #GNUNET_OK if the message was well-formed | ||
427 | */ | ||
428 | static int | ||
429 | check_address_list (void *cls, | ||
430 | const struct PeerInformationMessage *pi) | ||
431 | { | ||
432 | const char *plugin_address; | ||
433 | const char *plugin_name; | ||
434 | uint16_t plugin_address_length; | ||
435 | uint16_t plugin_name_length; | ||
436 | |||
437 | plugin_address_length = ntohs (pi->address_length); | ||
438 | plugin_name_length = ntohs (pi->plugin_name_length); | ||
439 | plugin_address = (const char *) &pi[1]; | ||
440 | plugin_name = &plugin_address[plugin_address_length]; | ||
441 | if ((plugin_address_length + plugin_name_length | ||
442 | + sizeof(struct PeerInformationMessage) != ntohs (pi->header.size)) || | ||
443 | (plugin_name[plugin_name_length - 1] != '\0')) | ||
444 | { | ||
445 | GNUNET_break (0); | ||
446 | return GNUNET_SYSERR; | ||
447 | } | ||
448 | return GNUNET_OK; | ||
449 | } | ||
450 | |||
451 | |||
452 | /** | ||
453 | * We received a #GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE. | ||
454 | * Process it. | ||
455 | * | ||
456 | * @param cls our context with the callback | ||
457 | * @param pi the message | ||
458 | */ | ||
459 | static void | ||
460 | handle_address_list (void *cls, | ||
461 | const struct PeerInformationMessage *pi) | ||
462 | { | ||
463 | struct GNUNET_ATS_PerformanceHandle *ph = cls; | ||
464 | struct GNUNET_ATS_AddressListHandle *alh; | ||
465 | struct GNUNET_ATS_AddressListHandle *next; | ||
466 | const char *plugin_address; | ||
467 | const char *plugin_name; | ||
468 | struct GNUNET_HELLO_Address address; | ||
469 | struct GNUNET_PeerIdentity allzeros; | ||
470 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_zero; | ||
471 | struct GNUNET_ATS_Properties prop; | ||
472 | uint16_t plugin_address_length; | ||
473 | uint16_t plugin_name_length; | ||
474 | uint32_t active; | ||
475 | uint32_t id; | ||
476 | |||
477 | id = ntohl (pi->id); | ||
478 | active = ntohl (pi->address_active); | ||
479 | plugin_address_length = ntohs (pi->address_length); | ||
480 | plugin_name_length = ntohs (pi->plugin_name_length); | ||
481 | plugin_address = (const char *) &pi[1]; | ||
482 | plugin_name = &plugin_address[plugin_address_length]; | ||
483 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
484 | "Received ATS_ADDRESSLIST_RESPONSE message for peer %s and plugin %s\n", | ||
485 | GNUNET_i2s (&pi->peer), | ||
486 | plugin_name); | ||
487 | |||
488 | next = ph->addresslist_head; | ||
489 | while (NULL != (alh = next)) | ||
490 | { | ||
491 | next = alh->next; | ||
492 | if (alh->id == id) | ||
493 | break; | ||
494 | } | ||
495 | if (NULL == alh) | ||
496 | return; /* was canceled */ | ||
497 | |||
498 | memset (&allzeros, '\0', sizeof(allzeros)); | ||
499 | if ((GNUNET_YES == GNUNET_is_zero (&pi->peer)) && | ||
500 | (0 == plugin_name_length) && | ||
501 | (0 == plugin_address_length)) | ||
502 | { | ||
503 | /* Done */ | ||
504 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
505 | "Received last message for ATS_ADDRESSLIST_RESPONSE\n"); | ||
506 | bandwidth_zero.value__ = htonl (0); | ||
507 | GNUNET_CONTAINER_DLL_remove (ph->addresslist_head, | ||
508 | ph->addresslist_tail, | ||
509 | alh); | ||
510 | if (NULL != alh->cb) | ||
511 | alh->cb (alh->cb_cls, | ||
512 | NULL, | ||
513 | GNUNET_NO, | ||
514 | bandwidth_zero, | ||
515 | bandwidth_zero, | ||
516 | NULL); | ||
517 | GNUNET_free (alh); | ||
518 | return; | ||
519 | } | ||
520 | |||
521 | address.peer = pi->peer; | ||
522 | address.address = plugin_address; | ||
523 | address.address_length = plugin_address_length; | ||
524 | address.transport_name = plugin_name; | ||
525 | if (((GNUNET_YES == alh->all_addresses) || | ||
526 | (GNUNET_YES == active)) && | ||
527 | (NULL != alh->cb)) | ||
528 | { | ||
529 | GNUNET_ATS_properties_ntoh (&prop, | ||
530 | &pi->properties); | ||
531 | alh->cb (alh->cb_cls, | ||
532 | &address, | ||
533 | active, | ||
534 | pi->bandwidth_out, | ||
535 | pi->bandwidth_in, | ||
536 | &prop); | ||
537 | } | ||
538 | } | ||
539 | |||
540 | |||
541 | /** | ||
542 | * Generic error handler, called with the appropriate error code and | ||
543 | * the same closure specified at the creation of the message queue. | ||
544 | * Not every message queue implementation supports an error handler. | ||
545 | * | ||
546 | * @param cls closure with the `struct GNUNET_ATS_PerformanceHandle *` | ||
547 | * @param error error code | ||
548 | */ | ||
549 | static void | ||
550 | mq_error_handler (void *cls, | ||
551 | enum GNUNET_MQ_Error error) | ||
552 | { | ||
553 | struct GNUNET_ATS_PerformanceHandle *ph = cls; | ||
554 | |||
555 | do_reconnect (ph); | ||
556 | } | ||
557 | |||
558 | |||
559 | /** | ||
560 | * Re-establish the connection to the ATS service. | ||
561 | * | ||
562 | * @param ph handle to use to re-connect. | ||
563 | */ | ||
564 | static void | ||
565 | reconnect (struct GNUNET_ATS_PerformanceHandle *ph) | ||
566 | { | ||
567 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
568 | GNUNET_MQ_hd_var_size (peer_information, | ||
569 | GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION, | ||
570 | struct PeerInformationMessage, | ||
571 | ph), | ||
572 | GNUNET_MQ_hd_fixed_size (reservation_result, | ||
573 | GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT, | ||
574 | struct ReservationResultMessage, | ||
575 | ph), | ||
576 | GNUNET_MQ_hd_var_size (address_list, | ||
577 | GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE, | ||
578 | struct PeerInformationMessage, | ||
579 | ph), | ||
580 | GNUNET_MQ_handler_end () | ||
581 | }; | ||
582 | struct GNUNET_MQ_Envelope *env; | ||
583 | struct ClientStartMessage *init; | ||
584 | |||
585 | GNUNET_assert (NULL == ph->mq); | ||
586 | ph->mq = GNUNET_CLIENT_connect (ph->cfg, | ||
587 | "ats", | ||
588 | handlers, | ||
589 | &mq_error_handler, | ||
590 | ph); | ||
591 | if (NULL == ph->mq) | ||
592 | return; | ||
593 | env = GNUNET_MQ_msg (init, | ||
594 | GNUNET_MESSAGE_TYPE_ATS_START); | ||
595 | init->start_flag = htonl ((NULL == ph->addr_info_cb) | ||
596 | ? START_FLAG_PERFORMANCE_NO_PIC | ||
597 | : START_FLAG_PERFORMANCE_WITH_PIC); | ||
598 | GNUNET_MQ_send (ph->mq, | ||
599 | env); | ||
600 | } | ||
601 | |||
602 | |||
603 | /** | ||
604 | * Get handle to access performance API of the ATS subsystem. | ||
605 | * | ||
606 | * @param cfg configuration to use | ||
607 | * @param addr_info_cb callback called when performance characteristics for | ||
608 | * an address change | ||
609 | * @param addr_info_cb_cls closure for @a addr_info_cb | ||
610 | * @return ats performance context | ||
611 | */ | ||
612 | struct GNUNET_ATS_PerformanceHandle * | ||
613 | GNUNET_ATS_performance_init (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
614 | GNUNET_ATS_AddressInformationCallback addr_info_cb, | ||
615 | void *addr_info_cb_cls) | ||
616 | { | ||
617 | struct GNUNET_ATS_PerformanceHandle *ph; | ||
618 | |||
619 | ph = GNUNET_new (struct GNUNET_ATS_PerformanceHandle); | ||
620 | ph->cfg = cfg; | ||
621 | ph->addr_info_cb = addr_info_cb; | ||
622 | ph->addr_info_cb_cls = addr_info_cb_cls; | ||
623 | reconnect (ph); | ||
624 | if (NULL == ph->mq) | ||
625 | { | ||
626 | GNUNET_free (ph); | ||
627 | return NULL; | ||
628 | } | ||
629 | return ph; | ||
630 | } | ||
631 | |||
632 | |||
633 | /** | ||
634 | * Client is done using the ATS performance subsystem, release resources. | ||
635 | * | ||
636 | * @param ph handle | ||
637 | */ | ||
638 | void | ||
639 | GNUNET_ATS_performance_done (struct GNUNET_ATS_PerformanceHandle *ph) | ||
640 | { | ||
641 | struct GNUNET_ATS_ReservationContext *rc; | ||
642 | struct GNUNET_ATS_AddressListHandle *alh; | ||
643 | |||
644 | while (NULL != (alh = ph->addresslist_head)) | ||
645 | { | ||
646 | GNUNET_CONTAINER_DLL_remove (ph->addresslist_head, | ||
647 | ph->addresslist_tail, | ||
648 | alh); | ||
649 | GNUNET_free (alh); | ||
650 | } | ||
651 | while (NULL != (rc = ph->reservation_head)) | ||
652 | { | ||
653 | GNUNET_CONTAINER_DLL_remove (ph->reservation_head, | ||
654 | ph->reservation_tail, | ||
655 | rc); | ||
656 | GNUNET_break (NULL == rc->rcb); | ||
657 | GNUNET_free (rc); | ||
658 | } | ||
659 | if (NULL != ph->task) | ||
660 | { | ||
661 | GNUNET_SCHEDULER_cancel (ph->task); | ||
662 | ph->task = NULL; | ||
663 | } | ||
664 | if (NULL != ph->mq) | ||
665 | { | ||
666 | GNUNET_MQ_destroy (ph->mq); | ||
667 | ph->mq = NULL; | ||
668 | } | ||
669 | GNUNET_free (ph); | ||
670 | } | ||
671 | |||
672 | |||
673 | /** | ||
674 | * Reserve inbound bandwidth from the given peer. ATS will look at | ||
675 | * the current amount of traffic we receive from the peer and ensure | ||
676 | * that the peer could add @a amount of data to its stream. | ||
677 | * | ||
678 | * @param ph performance handle | ||
679 | * @param peer identifies the peer | ||
680 | * @param amount reserve N bytes for receiving, negative | ||
681 | * amounts can be used to undo a (recent) reservation; | ||
682 | * @param rcb function to call with the resulting reservation information | ||
683 | * @param rcb_cls closure for @a rcb | ||
684 | * @return NULL on error | ||
685 | * @deprecated will be replaced soon | ||
686 | */ | ||
687 | struct GNUNET_ATS_ReservationContext * | ||
688 | GNUNET_ATS_reserve_bandwidth (struct GNUNET_ATS_PerformanceHandle *ph, | ||
689 | const struct GNUNET_PeerIdentity *peer, | ||
690 | int32_t amount, | ||
691 | GNUNET_ATS_ReservationCallback rcb, | ||
692 | void *rcb_cls) | ||
693 | { | ||
694 | struct GNUNET_ATS_ReservationContext *rc; | ||
695 | struct GNUNET_MQ_Envelope *env; | ||
696 | struct ReservationRequestMessage *m; | ||
697 | |||
698 | if (NULL == ph->mq) | ||
699 | return NULL; | ||
700 | rc = GNUNET_new (struct GNUNET_ATS_ReservationContext); | ||
701 | rc->size = amount; | ||
702 | rc->peer = *peer; | ||
703 | rc->rcb = rcb; | ||
704 | rc->rcb_cls = rcb_cls; | ||
705 | if ((NULL != rcb) && | ||
706 | (amount > 0)) | ||
707 | rc->undo = GNUNET_YES; | ||
708 | GNUNET_CONTAINER_DLL_insert_tail (ph->reservation_head, | ||
709 | ph->reservation_tail, | ||
710 | rc); | ||
711 | env = GNUNET_MQ_msg (m, | ||
712 | GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST); | ||
713 | m->amount = htonl (amount); | ||
714 | m->peer = *peer; | ||
715 | GNUNET_MQ_send (ph->mq, | ||
716 | env); | ||
717 | return rc; | ||
718 | } | ||
719 | |||
720 | |||
721 | /** | ||
722 | * Cancel request for reserving bandwidth. | ||
723 | * | ||
724 | * @param rc context returned by the original #GNUNET_ATS_reserve_bandwidth() call | ||
725 | */ | ||
726 | void | ||
727 | GNUNET_ATS_reserve_bandwidth_cancel (struct GNUNET_ATS_ReservationContext *rc) | ||
728 | { | ||
729 | rc->rcb = NULL; | ||
730 | } | ||
731 | |||
732 | |||
733 | /** | ||
734 | * Get information about addresses known to the ATS subsystem. | ||
735 | * | ||
736 | * @param ph the performance handle to use | ||
737 | * @param peer peer idm can be NULL for all peers | ||
738 | * @param all #GNUNET_YES to get information about all addresses or #GNUNET_NO to | ||
739 | * get only address currently used | ||
740 | * @param infocb callback to call with the addresses, | ||
741 | * will callback with address == NULL when done | ||
742 | * @param infocb_cls closure for @a infocb | ||
743 | * @return ats performance context | ||
744 | */ | ||
745 | struct GNUNET_ATS_AddressListHandle* | ||
746 | GNUNET_ATS_performance_list_addresses (struct GNUNET_ATS_PerformanceHandle *ph, | ||
747 | const struct GNUNET_PeerIdentity *peer, | ||
748 | int all, | ||
749 | GNUNET_ATS_AddressInformationCallback | ||
750 | infocb, | ||
751 | void *infocb_cls) | ||
752 | { | ||
753 | struct GNUNET_ATS_AddressListHandle *alh; | ||
754 | struct GNUNET_MQ_Envelope *env; | ||
755 | struct AddressListRequestMessage *m; | ||
756 | |||
757 | if (NULL == ph->mq) | ||
758 | return NULL; | ||
759 | if (NULL == infocb) | ||
760 | { | ||
761 | GNUNET_break (0); | ||
762 | return NULL; | ||
763 | } | ||
764 | alh = GNUNET_new (struct GNUNET_ATS_AddressListHandle); | ||
765 | alh->id = ph->id++; | ||
766 | alh->cb = infocb; | ||
767 | alh->cb_cls = infocb_cls; | ||
768 | alh->ph = ph; | ||
769 | alh->all_addresses = all; | ||
770 | if (NULL == peer) | ||
771 | { | ||
772 | alh->all_peers = GNUNET_YES; | ||
773 | } | ||
774 | else | ||
775 | { | ||
776 | alh->all_peers = GNUNET_NO; | ||
777 | alh->peer = *peer; | ||
778 | } | ||
779 | GNUNET_CONTAINER_DLL_insert (ph->addresslist_head, | ||
780 | ph->addresslist_tail, | ||
781 | alh); | ||
782 | env = GNUNET_MQ_msg (m, | ||
783 | GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_REQUEST); | ||
784 | m->all = htonl (all); | ||
785 | m->id = htonl (alh->id); | ||
786 | if (NULL != peer) | ||
787 | m->peer = *peer; | ||
788 | GNUNET_MQ_send (ph->mq, | ||
789 | env); | ||
790 | return alh; | ||
791 | } | ||
792 | |||
793 | |||
794 | /** | ||
795 | * Cancel a pending address listing operation | ||
796 | * | ||
797 | * @param alh the handle of the request to cancel | ||
798 | */ | ||
799 | void | ||
800 | GNUNET_ATS_performance_list_addresses_cancel (struct | ||
801 | GNUNET_ATS_AddressListHandle *alh) | ||
802 | { | ||
803 | struct GNUNET_ATS_PerformanceHandle *ph = alh->ph; | ||
804 | |||
805 | GNUNET_CONTAINER_DLL_remove (ph->addresslist_head, | ||
806 | ph->addresslist_tail, | ||
807 | alh); | ||
808 | GNUNET_free (alh); | ||
809 | } | ||
810 | |||
811 | |||
812 | /** | ||
813 | * Convert a `enum GNUNET_ATS_PreferenceType` to a string | ||
814 | * | ||
815 | * @param type the preference type | ||
816 | * @return a string or NULL if invalid | ||
817 | */ | ||
818 | const char * | ||
819 | GNUNET_ATS_print_preference_type (enum GNUNET_ATS_PreferenceKind type) | ||
820 | { | ||
821 | const char *prefs[] = GNUNET_ATS_PreferenceTypeString; | ||
822 | |||
823 | if (type < GNUNET_ATS_PREFERENCE_END) | ||
824 | return prefs[type]; | ||
825 | return NULL; | ||
826 | } | ||
827 | |||
828 | |||
829 | /** | ||
830 | * Change preferences for the given peer. Preference changes are forgotten if peers | ||
831 | * disconnect. | ||
832 | * | ||
833 | * @param ph performance handle | ||
834 | * @param peer identifies the peer | ||
835 | * @param ... #GNUNET_ATS_PREFERENCE_END-terminated specification of the desired changes | ||
836 | */ | ||
837 | void | ||
838 | GNUNET_ATS_performance_change_preference (struct | ||
839 | GNUNET_ATS_PerformanceHandle *ph, | ||
840 | const struct | ||
841 | GNUNET_PeerIdentity *peer, | ||
842 | ...) | ||
843 | { | ||
844 | struct GNUNET_MQ_Envelope *env; | ||
845 | struct ChangePreferenceMessage *m; | ||
846 | uint32_t count; | ||
847 | struct PreferenceInformation *pi; | ||
848 | va_list ap; | ||
849 | enum GNUNET_ATS_PreferenceKind kind; | ||
850 | |||
851 | if (NULL == ph->mq) | ||
852 | return; | ||
853 | count = 0; | ||
854 | va_start (ap, peer); | ||
855 | while (GNUNET_ATS_PREFERENCE_END != | ||
856 | (kind = GNUNET_VA_ARG_ENUM (ap, GNUNET_ATS_PreferenceKind))) | ||
857 | { | ||
858 | switch (kind) | ||
859 | { | ||
860 | case GNUNET_ATS_PREFERENCE_BANDWIDTH: | ||
861 | count++; | ||
862 | (void) va_arg (ap, double); | ||
863 | break; | ||
864 | |||
865 | case GNUNET_ATS_PREFERENCE_LATENCY: | ||
866 | count++; | ||
867 | (void) va_arg (ap, double); | ||
868 | break; | ||
869 | |||
870 | default: | ||
871 | GNUNET_assert (0); | ||
872 | } | ||
873 | } | ||
874 | va_end (ap); | ||
875 | env = GNUNET_MQ_msg_extra (m, | ||
876 | count * sizeof(struct PreferenceInformation), | ||
877 | GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE); | ||
878 | m->num_preferences = htonl (count); | ||
879 | m->peer = *peer; | ||
880 | pi = (struct PreferenceInformation *) &m[1]; | ||
881 | count = 0; | ||
882 | va_start (ap, peer); | ||
883 | while (GNUNET_ATS_PREFERENCE_END != (kind = | ||
884 | GNUNET_VA_ARG_ENUM (ap, | ||
885 | GNUNET_ATS_PreferenceKind))) | ||
886 | { | ||
887 | pi[count].preference_kind = htonl (kind); | ||
888 | switch (kind) | ||
889 | { | ||
890 | case GNUNET_ATS_PREFERENCE_BANDWIDTH: | ||
891 | pi[count].preference_value = (float) va_arg (ap, double); | ||
892 | |||
893 | count++; | ||
894 | break; | ||
895 | |||
896 | case GNUNET_ATS_PREFERENCE_LATENCY: | ||
897 | pi[count].preference_value = (float) va_arg (ap, double); | ||
898 | |||
899 | count++; | ||
900 | break; | ||
901 | |||
902 | default: | ||
903 | GNUNET_assert (0); | ||
904 | } | ||
905 | } | ||
906 | va_end (ap); | ||
907 | GNUNET_MQ_send (ph->mq, | ||
908 | env); | ||
909 | } | ||
910 | |||
911 | |||
912 | /** | ||
913 | * Send feedback to ATS on how good a the requirements for a peer and a | ||
914 | * preference is satisfied by ATS | ||
915 | * | ||
916 | * @param ph performance handle | ||
917 | * @param scope the time interval this valid for: [now - scope .. now] | ||
918 | * @param peer identifies the peer | ||
919 | * @param ... #GNUNET_ATS_PREFERENCE_END-terminated specification of the desired changes | ||
920 | */ | ||
921 | void | ||
922 | GNUNET_ATS_performance_give_feedback (struct GNUNET_ATS_PerformanceHandle *ph, | ||
923 | const struct GNUNET_PeerIdentity *peer, | ||
924 | const struct GNUNET_TIME_Relative scope, | ||
925 | ...) | ||
926 | { | ||
927 | struct GNUNET_MQ_Envelope *env; | ||
928 | struct FeedbackPreferenceMessage *m; | ||
929 | uint32_t count; | ||
930 | struct PreferenceInformation *pi; | ||
931 | va_list ap; | ||
932 | enum GNUNET_ATS_PreferenceKind kind; | ||
933 | |||
934 | if (NULL == ph->mq) | ||
935 | return; | ||
936 | count = 0; | ||
937 | va_start (ap, scope); | ||
938 | while (GNUNET_ATS_PREFERENCE_END != | ||
939 | (kind = GNUNET_VA_ARG_ENUM (ap, GNUNET_ATS_PreferenceKind))) | ||
940 | { | ||
941 | switch (kind) | ||
942 | { | ||
943 | case GNUNET_ATS_PREFERENCE_BANDWIDTH: | ||
944 | count++; | ||
945 | (void) va_arg (ap, double); | ||
946 | break; | ||
947 | |||
948 | case GNUNET_ATS_PREFERENCE_LATENCY: | ||
949 | count++; | ||
950 | (void) va_arg (ap, double); | ||
951 | break; | ||
952 | |||
953 | default: | ||
954 | GNUNET_assert (0); | ||
955 | } | ||
956 | } | ||
957 | va_end (ap); | ||
958 | env = GNUNET_MQ_msg_extra (m, | ||
959 | count * sizeof(struct PreferenceInformation), | ||
960 | GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_FEEDBACK); | ||
961 | m->scope = GNUNET_TIME_relative_hton (scope); | ||
962 | m->num_feedback = htonl (count); | ||
963 | m->peer = *peer; | ||
964 | pi = (struct PreferenceInformation *) &m[1]; | ||
965 | count = 0; | ||
966 | va_start (ap, scope); | ||
967 | while (GNUNET_ATS_PREFERENCE_END != (kind = | ||
968 | GNUNET_VA_ARG_ENUM (ap, | ||
969 | GNUNET_ATS_PreferenceKind))) | ||
970 | { | ||
971 | pi[count].preference_kind = htonl (kind); | ||
972 | switch (kind) | ||
973 | { | ||
974 | case GNUNET_ATS_PREFERENCE_BANDWIDTH: | ||
975 | pi[count].preference_value = (float) va_arg (ap, double); | ||
976 | |||
977 | count++; | ||
978 | break; | ||
979 | |||
980 | case GNUNET_ATS_PREFERENCE_LATENCY: | ||
981 | pi[count].preference_value = (float) va_arg (ap, double); | ||
982 | |||
983 | count++; | ||
984 | break; | ||
985 | |||
986 | default: | ||
987 | GNUNET_assert (0); | ||
988 | } | ||
989 | } | ||
990 | va_end (ap); | ||
991 | GNUNET_MQ_send (ph->mq, | ||
992 | env); | ||
993 | } | ||
994 | |||
995 | |||
996 | /* end of ats_api_performance.c */ | ||