aboutsummaryrefslogtreecommitdiff
path: root/src/ats/ats_api_performance.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ats/ats_api_performance.c')
-rw-r--r--src/ats/ats_api_performance.c996
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 */
38struct 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 */
85struct 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 */
137struct 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 */
215static void
216reconnect (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 */
224static void
225reconnect_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 */
239static void
240do_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 */
302static int
303check_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 */
333static void
334handle_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 */
375static void
376handle_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 */
428static int
429check_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 */
459static void
460handle_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 */
549static void
550mq_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 */
564static void
565reconnect (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 */
612struct GNUNET_ATS_PerformanceHandle *
613GNUNET_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 */
638void
639GNUNET_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 */
687struct GNUNET_ATS_ReservationContext *
688GNUNET_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 */
726void
727GNUNET_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 */
745struct GNUNET_ATS_AddressListHandle*
746GNUNET_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 */
799void
800GNUNET_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 */
818const char *
819GNUNET_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 */
837void
838GNUNET_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 */
921void
922GNUNET_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 */