2 This file is part of GNUnet.
3 (C) 2010,2011 Christian Grothoff (and other contributing authors)
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.
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.
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.
21 * @file ats/ats_api_performance.c
22 * @brief automatic transport selection and outbound bandwidth determination
23 * @author Christian Grothoff
24 * @author Matthias Wachs
27 #include "gnunet_ats_service.h"
32 * Message in linked list we should send to the ATS service. The
33 * actual binary message follows this struct.
41 struct PendingMessage *next;
46 struct PendingMessage *prev;
49 * Size of the message.
54 * Is this the 'ATS_START' message?
61 * Linked list of pending reservations.
63 struct GNUNET_ATS_ReservationContext
69 struct GNUNET_ATS_ReservationContext *next;
74 struct GNUNET_ATS_ReservationContext *prev;
79 struct GNUNET_PeerIdentity peer;
87 * Function to call on result.
89 GNUNET_ATS_ReservationCallback rcb;
97 * Do we need to undo this reservation if it succeeded? Set to
98 * GNUNET_YES if a reservation is cancelled. (at that point, 'info'
99 * is also set to NULL; however, info will ALSO be NULL for the
100 * reservation context that is created to undo the original request,
101 * so 'info' being NULL cannot be used to check if undo is
109 * Linked list of pending reservations.
111 struct GNUNET_ATS_AddressListHandle
117 struct GNUNET_ATS_AddressListHandle *next;
122 struct GNUNET_ATS_AddressListHandle *prev;
127 struct GNUNET_ATS_PerformanceHandle *ph;
132 GNUNET_ATS_AddressInformationCallback cb;
142 struct GNUNET_PeerIdentity peer;
145 * Return all or specific peer only
150 * Return all or used address only
155 * Request multiplexing
163 * ATS Handle to obtain and/or modify performance information.
165 struct GNUNET_ATS_PerformanceHandle
171 const struct GNUNET_CONFIGURATION_Handle *cfg;
174 * Callback to invoke when an address has performance changes.
176 GNUNET_ATS_AddressInformationCallback addr_info_cb;
179 * Closure for 'addr_info_cb'.
181 void *addr_info_cb_cls;
184 * Connection to ATS service.
186 struct GNUNET_CLIENT_Connection *client;
189 * Head of list of messages for the ATS service.
191 struct PendingMessage *pending_head;
194 * Tail of list of messages for the ATS service
196 struct PendingMessage *pending_tail;
199 * Head of linked list of pending reservation requests.
201 struct GNUNET_ATS_ReservationContext *reservation_head;
204 * Tail of linked list of pending reservation requests.
206 struct GNUNET_ATS_ReservationContext *reservation_tail;
209 * Head of linked list of pending address list requests.
211 struct GNUNET_ATS_AddressListHandle *addresslist_head;
214 * Tail of linked list of pending address list requests.
216 struct GNUNET_ATS_AddressListHandle *addresslist_tail;
220 * Current request for transmission to ATS.
222 struct GNUNET_CLIENT_TransmitHandle *th;
225 * Task to trigger reconnect.
227 GNUNET_SCHEDULER_TaskIdentifier task;
230 * Monitor request multiplexing
235 * Request multiplexing
242 * Re-establish the connection to the ATS service.
244 * @param ph handle to use to re-connect.
247 reconnect (struct GNUNET_ATS_PerformanceHandle *ph);
251 * Re-establish the connection to the ATS service.
253 * @param cls handle to use to re-connect.
254 * @param tc scheduler context
257 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
259 struct GNUNET_ATS_PerformanceHandle *ph = cls;
261 ph->task = GNUNET_SCHEDULER_NO_TASK;
267 * Transmit messages from the message queue to the service
268 * (if there are any, and if we are not already trying).
270 * @param ph handle to use
273 do_transmit (struct GNUNET_ATS_PerformanceHandle *ph);
277 * Type of a function to call when we receive a message
280 * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
281 * @param msg message received, NULL on timeout or fatal error
284 process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg);
287 * We can now transmit a message to ATS. Do it.
289 * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
290 * @param size number of bytes we can transmit to ATS
291 * @param buf where to copy the messages
292 * @return number of bytes copied into buf
295 transmit_message_to_ats (void *cls, size_t size, void *buf)
297 struct GNUNET_ATS_PerformanceHandle *ph = cls;
298 struct PendingMessage *p;
305 while ((NULL != (p = ph->pending_head)) && (p->size <= size))
307 memcpy (&cbuf[ret], &p[1], p->size);
310 GNUNET_CONTAINER_DLL_remove (ph->pending_head, ph->pending_tail, p);
311 if (GNUNET_YES == p->is_init)
312 GNUNET_CLIENT_receive (ph->client, &process_ats_message, ph,
313 GNUNET_TIME_UNIT_FOREVER_REL);
323 * Transmit messages from the message queue to the service
324 * (if there are any, and if we are not already trying).
326 * @param ph handle to use
329 do_transmit (struct GNUNET_ATS_PerformanceHandle *ph)
331 struct PendingMessage *p;
335 if (NULL == (p = ph->pending_head))
337 if (NULL == ph->client)
338 return; /* currently reconnecting */
340 GNUNET_CLIENT_notify_transmit_ready (ph->client, p->size,
341 GNUNET_TIME_UNIT_FOREVER_REL,
342 GNUNET_YES, &transmit_message_to_ats,
348 * We received a peer information message. Validate and process it.
350 * @param ph our context with the callback
351 * @param msg the message
352 * @return GNUNET_OK if the message was well-formed
355 process_pi_message (struct GNUNET_ATS_PerformanceHandle *ph,
356 const struct GNUNET_MessageHeader *msg)
358 const struct PeerInformationMessage *pi;
359 const struct GNUNET_ATS_Information *atsi;
360 const char *plugin_address;
361 const char *plugin_name;
362 struct GNUNET_HELLO_Address address;
363 uint16_t plugin_address_length;
364 uint16_t plugin_name_length;
368 if (ntohs (msg->size) < sizeof (struct PeerInformationMessage))
371 return GNUNET_SYSERR;
374 pi = (const struct PeerInformationMessage *) msg;
375 ats_count = ntohl (pi->ats_count);
376 plugin_address_length = ntohs (pi->address_length);
377 plugin_name_length = ntohs (pi->plugin_name_length);
378 addr_active = ntohl (pi->address_active);
379 atsi = (const struct GNUNET_ATS_Information *) &pi[1];
380 plugin_address = (const char *) &atsi[ats_count];
381 plugin_name = &plugin_address[plugin_address_length];
382 if ((plugin_address_length + plugin_name_length +
383 ats_count * sizeof (struct GNUNET_ATS_Information) +
384 sizeof (struct PeerInformationMessage) != ntohs (msg->size)) ||
386 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information))
387 || (plugin_name[plugin_name_length - 1] != '\0'))
390 return GNUNET_SYSERR;
393 if (NULL != ph->addr_info_cb)
395 address.peer = pi->peer;
396 address.address = plugin_address;
397 address.address_length = plugin_address_length;
398 address.transport_name = plugin_name;
400 ph->addr_info_cb (ph->addr_info_cb_cls, &address, addr_active, pi->bandwidth_out, pi->bandwidth_in,
408 * We received a reservation result message. Validate and process it.
410 * @param ph our context with the callback
411 * @param msg the message
412 * @return GNUNET_OK if the message was well-formed
415 process_rr_message (struct GNUNET_ATS_PerformanceHandle *ph,
416 const struct GNUNET_MessageHeader *msg)
418 const struct ReservationResultMessage *rr;
419 struct GNUNET_ATS_ReservationContext *rc;
422 if (ntohs (msg->size) < sizeof (struct ReservationResultMessage))
425 return GNUNET_SYSERR;
427 rr = (const struct ReservationResultMessage *) msg;
428 amount = ntohl (rr->amount);
429 rc = ph->reservation_head;
430 if (0 != memcmp (&rr->peer, &rc->peer, sizeof (struct GNUNET_PeerIdentity)))
433 return GNUNET_SYSERR;
435 GNUNET_CONTAINER_DLL_remove (ph->reservation_head, ph->reservation_tail, rc);
436 if ((amount == 0) || (rc->rcb != NULL))
438 /* tell client if not cancelled */
440 rc->rcb (rc->rcb_cls, &rr->peer, amount,
441 GNUNET_TIME_relative_ntoh (rr->res_delay));
445 /* amount non-zero, but client cancelled, consider undo! */
446 if (GNUNET_YES != rc->undo)
449 return GNUNET_OK; /* do not try to undo failed undos or negative amounts */
452 (void) GNUNET_ATS_reserve_bandwidth (ph, &rr->peer, -amount, NULL, NULL);
458 * We received a reservation result message. Validate and process it.
460 * @param ph our context with the callback
461 * @param msg the message
462 * @return GNUNET_OK if the message was well-formed
465 process_ar_message (struct GNUNET_ATS_PerformanceHandle *ph,
466 const struct GNUNET_MessageHeader *msg)
468 const struct PeerInformationMessage *pi;
469 struct GNUNET_ATS_AddressListHandle *alh;
470 struct GNUNET_ATS_AddressListHandle *next;
471 const struct GNUNET_ATS_Information *atsi;
472 const char *plugin_address;
473 const char *plugin_name;
474 struct GNUNET_HELLO_Address address;
475 struct GNUNET_PeerIdentity allzeros;
476 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_zero;
477 uint16_t plugin_address_length;
478 uint16_t plugin_name_length;
483 if (ntohs (msg->size) < sizeof (struct PeerInformationMessage))
486 return GNUNET_SYSERR;
488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
489 _("Received %s message\n"), "ATS_ADDRESSLIST_RESPONSE");
491 pi = (const struct PeerInformationMessage *) msg;
493 ats_count = ntohl (pi->ats_count);
494 active = ntohl (pi->address_active);
495 plugin_address_length = ntohs (pi->address_length);
496 plugin_name_length = ntohs (pi->plugin_name_length);
497 atsi = (const struct GNUNET_ATS_Information *) &pi[1];
498 plugin_address = (const char *) &atsi[ats_count];
499 plugin_name = &plugin_address[plugin_address_length];
500 if ((plugin_address_length + plugin_name_length +
501 ats_count * sizeof (struct GNUNET_ATS_Information) +
502 sizeof (struct PeerInformationMessage) != ntohs (msg->size)) ||
504 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information))
505 || (plugin_name[plugin_name_length - 1] != '\0'))
508 return GNUNET_SYSERR;
511 next = ph->addresslist_head;
512 while (NULL != (alh = next))
521 return GNUNET_SYSERR;
524 memset (&allzeros, '\0', sizeof (allzeros));
525 if ((0 == memcmp (&allzeros, &pi->peer, sizeof (allzeros))) &&
526 (0 == plugin_name_length) &&
527 (0 == plugin_address_length) &&
531 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
532 _("Received last message for %s \n"), "ATS_ADDRESSLIST_RESPONSE");
533 bandwidth_zero.value__ = htonl (0);
535 alh->cb (ph->addr_info_cb_cls,
538 bandwidth_zero, bandwidth_zero,
540 GNUNET_CONTAINER_DLL_remove (ph->addresslist_head, ph->addresslist_tail, alh);
545 address.peer = pi->peer;
546 address.address = plugin_address;
547 address.address_length = plugin_address_length;
548 address.transport_name = plugin_name;
550 if ((GNUNET_YES == alh->all_addresses) || (GNUNET_YES == active))
553 alh->cb (ph->addr_info_cb_cls,
556 pi->bandwidth_out, pi->bandwidth_in,
564 * Type of a function to call when we receive a message
567 * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
568 * @param msg message received, NULL on timeout or fatal error
571 process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg)
573 struct GNUNET_ATS_PerformanceHandle *ph = cls;
577 switch (ntohs (msg->type))
579 case GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION:
580 if (GNUNET_OK != process_pi_message (ph, msg))
583 case GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT:
584 if (GNUNET_OK != process_rr_message (ph, msg))
587 case GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE:
588 if (GNUNET_OK != process_ar_message (ph, msg))
595 GNUNET_CLIENT_receive (ph->client, &process_ats_message, ph,
596 GNUNET_TIME_UNIT_FOREVER_REL);
601 GNUNET_CLIENT_notify_transmit_ready_cancel (ph->th);
604 GNUNET_CLIENT_disconnect (ph->client);
607 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
613 * Re-establish the connection to the ATS service.
615 * @param ph handle to use to re-connect.
618 reconnect (struct GNUNET_ATS_PerformanceHandle *ph)
620 struct PendingMessage *p;
621 struct ClientStartMessage *init;
623 GNUNET_assert (NULL == ph->client);
624 ph->client = GNUNET_CLIENT_connect ("ats", ph->cfg);
625 GNUNET_assert (NULL != ph->client);
626 if ((NULL == (p = ph->pending_head)) || (GNUNET_YES != p->is_init))
628 p = GNUNET_malloc (sizeof (struct PendingMessage) +
629 sizeof (struct ClientStartMessage));
630 p->size = sizeof (struct ClientStartMessage);
631 p->is_init = GNUNET_YES;
632 init = (struct ClientStartMessage *) &p[1];
633 init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START);
634 init->header.size = htons (sizeof (struct ClientStartMessage));
636 htonl ((NULL ==ph->addr_info_cb) ?
637 START_FLAG_PERFORMANCE_NO_PIC : START_FLAG_PERFORMANCE_WITH_PIC);
638 GNUNET_CONTAINER_DLL_insert (ph->pending_head, ph->pending_tail, p);
646 * Get handle to access performance API of the ATS subsystem.
648 * @param cfg configuration to use
649 * @param addr_info_cb callback called when performance characteristics for
651 * @param addr_info_cb_cls closure for infocb
652 * @return ats performance context
654 struct GNUNET_ATS_PerformanceHandle *
655 GNUNET_ATS_performance_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
656 GNUNET_ATS_AddressInformationCallback addr_info_cb,
657 void *addr_info_cb_cls)
659 struct GNUNET_ATS_PerformanceHandle *ph;
661 ph = GNUNET_malloc (sizeof (struct GNUNET_ATS_PerformanceHandle));
663 ph->addr_info_cb = addr_info_cb;
664 ph->addr_info_cb_cls = addr_info_cb_cls;
671 * Client is done using the ATS performance subsystem, release resources.
676 GNUNET_ATS_performance_done (struct GNUNET_ATS_PerformanceHandle *ph)
678 struct PendingMessage *p;
679 struct GNUNET_ATS_ReservationContext *rc;
680 struct GNUNET_ATS_AddressListHandle *alh;
682 while (NULL != (p = ph->pending_head))
684 GNUNET_CONTAINER_DLL_remove (ph->pending_head, ph->pending_tail, p);
687 while (NULL != (alh = ph->addresslist_head))
689 GNUNET_CONTAINER_DLL_remove (ph->addresslist_head, ph->addresslist_tail,
693 while (NULL != (rc = ph->reservation_head))
695 GNUNET_CONTAINER_DLL_remove (ph->reservation_head, ph->reservation_tail,
697 GNUNET_break (NULL == rc->rcb);
701 if (GNUNET_SCHEDULER_NO_TASK != ph->task)
703 GNUNET_SCHEDULER_cancel (ph->task);
704 ph->task = GNUNET_SCHEDULER_NO_TASK;
706 if (NULL != ph->client)
708 GNUNET_CLIENT_disconnect (ph->client);
716 * Reserve inbound bandwidth from the given peer. ATS will look at
717 * the current amount of traffic we receive from the peer and ensure
718 * that the peer could add 'amount' of data to its stream.
720 * @param ph performance handle
721 * @param peer identifies the peer
722 * @param amount reserve N bytes for receiving, negative
723 * amounts can be used to undo a (recent) reservation;
724 * @param rcb function to call with the resulting reservation information
725 * @param rcb_cls closure for info
726 * @return NULL on error
727 * @deprecated will be replaced soon
729 struct GNUNET_ATS_ReservationContext *
730 GNUNET_ATS_reserve_bandwidth (struct GNUNET_ATS_PerformanceHandle *ph,
731 const struct GNUNET_PeerIdentity *peer,
733 GNUNET_ATS_ReservationCallback rcb, void *rcb_cls)
735 struct GNUNET_ATS_ReservationContext *rc;
736 struct PendingMessage *p;
737 struct ReservationRequestMessage *m;
739 rc = GNUNET_malloc (sizeof (struct GNUNET_ATS_ReservationContext));
743 rc->rcb_cls = rcb_cls;
744 if ((rcb != NULL) && (amount > 0))
745 rc->undo = GNUNET_YES;
746 GNUNET_CONTAINER_DLL_insert_tail (ph->reservation_head, ph->reservation_tail,
749 p = GNUNET_malloc (sizeof (struct PendingMessage) +
750 sizeof (struct ReservationRequestMessage));
751 p->size = sizeof (struct ReservationRequestMessage);
752 p->is_init = GNUNET_NO;
753 m = (struct ReservationRequestMessage *) &p[1];
754 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST);
755 m->header.size = htons (sizeof (struct ReservationRequestMessage));
756 m->amount = htonl (amount);
758 GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head, ph->pending_tail, p);
765 * Cancel request for reserving bandwidth.
767 * @param rc context returned by the original GNUNET_ATS_reserve_bandwidth call
770 GNUNET_ATS_reserve_bandwidth_cancel (struct GNUNET_ATS_ReservationContext *rc)
776 * Get information about addresses known to the ATS subsystem.
778 * @param handle the performance handle to use
779 * @param peer peer idm can be NULL for all peers
780 * @param all GNUNET_YES to get information about all addresses or GNUNET_NO to
781 * get only address currently used
782 * @param infocb callback to call with the addresses,
783 * will callback with address == NULL when done
784 * @param infocb_cls closure for infocb
785 * @return ats performance context
787 struct GNUNET_ATS_AddressListHandle*
788 GNUNET_ATS_performance_list_addresses (struct GNUNET_ATS_PerformanceHandle *handle,
789 const struct GNUNET_PeerIdentity *peer,
791 GNUNET_ATS_AddressInformationCallback infocb,
794 struct GNUNET_ATS_AddressListHandle *alh;
795 struct PendingMessage *p;
796 struct AddressListRequestMessage *m;
798 GNUNET_assert (NULL != handle);
802 alh = GNUNET_malloc (sizeof (struct GNUNET_ATS_AddressListHandle));
803 alh->id = handle->id;
806 alh->cb_cls = infocb_cls;
808 alh->all_addresses = all;
810 alh->all_peers = GNUNET_YES;
813 alh->all_peers = GNUNET_NO;
817 GNUNET_CONTAINER_DLL_insert (handle->addresslist_head, handle->addresslist_tail, alh);
819 p = GNUNET_malloc (sizeof (struct PendingMessage) +
820 sizeof (struct AddressListRequestMessage));
821 p->size = sizeof (struct AddressListRequestMessage);
822 m = (struct AddressListRequestMessage *) &p[1];
823 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_REQUEST);
824 m->header.size = htons (sizeof (struct AddressListRequestMessage));
825 m->all = htonl (all);
826 m->id = htonl (alh->id);
831 memset (&m->peer, '\0', sizeof (struct GNUNET_PeerIdentity));
833 GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head, handle->pending_tail, p);
835 do_transmit (handle);
842 * Cancel a pending address listing operation
844 * @param handle the GNUNET_ATS_AddressListHandle handle to cancel
847 GNUNET_ATS_performance_list_addresses_cancel (struct GNUNET_ATS_AddressListHandle *handle)
849 GNUNET_assert (NULL != handle);
851 GNUNET_CONTAINER_DLL_remove (handle->ph->addresslist_head, handle->ph->addresslist_tail, handle);
852 GNUNET_free (handle);
857 * Convert a GNUNET_ATS_PreferenceType to a string
859 * @param type the preference type
860 * @return a string or NULL if invalid
863 GNUNET_ATS_print_preference_type (uint32_t type)
865 char *prefs[GNUNET_ATS_PreferenceCount] = GNUNET_ATS_PreferenceTypeString;
866 if (type < GNUNET_ATS_PreferenceCount)
873 * Change preferences for the given peer. Preference changes are forgotten if peers
876 * @param ph performance handle
877 * @param peer identifies the peer
878 * @param ... 0-terminated specification of the desired changes
881 GNUNET_ATS_performance_change_preference (struct GNUNET_ATS_PerformanceHandle *ph,
882 const struct GNUNET_PeerIdentity *peer, ...)
884 struct PendingMessage *p;
885 struct ChangePreferenceMessage *m;
888 struct PreferenceInformation *pi;
890 enum GNUNET_ATS_PreferenceKind kind;
894 while (GNUNET_ATS_PREFERENCE_END !=
895 (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind)))
899 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
901 (void) va_arg (ap, double);
904 case GNUNET_ATS_PREFERENCE_LATENCY:
906 (void) va_arg (ap, double);
915 count * sizeof (struct PreferenceInformation) +
916 sizeof (struct ChangePreferenceMessage);
917 p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
919 p->is_init = GNUNET_NO;
920 m = (struct ChangePreferenceMessage *) &p[1];
921 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE);
922 m->header.size = htons (msize);
923 m->num_preferences = htonl (count);
925 pi = (struct PreferenceInformation *) &m[1];
928 while (GNUNET_ATS_PREFERENCE_END !=
929 (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind)))
931 pi[count].preference_kind = htonl (kind);
934 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
935 pi[count].preference_value = (float) va_arg (ap, double);
939 case GNUNET_ATS_PREFERENCE_LATENCY:
940 pi[count].preference_value = (float) va_arg (ap, double);
949 GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head, ph->pending_tail, p);
954 * Send feedback to ATS on how good a the requirements for a peer and a
955 * preference is satisfied by ATS
957 * @param ph performance handle
958 * @param scope the time interval this valid for: [now - scope .. now]
959 * @param peer identifies the peer
960 * @param ... 0-terminated specification of the desired changes
963 GNUNET_ATS_performance_give_feedback (struct GNUNET_ATS_PerformanceHandle *ph,
964 const struct GNUNET_PeerIdentity *peer,
965 const struct GNUNET_TIME_Relative scope, ...)
967 struct PendingMessage *p;
968 struct FeedbackPreferenceMessage *m;
971 struct PreferenceInformation *pi;
973 enum GNUNET_ATS_PreferenceKind kind;
976 va_start (ap, scope);
977 while (GNUNET_ATS_PREFERENCE_END !=
978 (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind)))
982 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
984 (void) va_arg (ap, double);
987 case GNUNET_ATS_PREFERENCE_LATENCY:
989 (void) va_arg (ap, double);
998 count * sizeof (struct PreferenceInformation) +
999 sizeof (struct FeedbackPreferenceMessage);
1000 p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
1002 p->is_init = GNUNET_NO;
1003 m = (struct FeedbackPreferenceMessage *) &p[1];
1004 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_FEEDBACK);
1005 m->header.size = htons (msize);
1006 m->scope = GNUNET_TIME_relative_hton (scope);
1007 m->num_feedback = htonl (count);
1009 pi = (struct PreferenceInformation *) &m[1];
1011 va_start (ap, scope);
1012 while (GNUNET_ATS_PREFERENCE_END !=
1013 (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind)))
1015 pi[count].preference_kind = htonl (kind);
1018 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
1019 pi[count].preference_value = (float) va_arg (ap, double);
1023 case GNUNET_ATS_PREFERENCE_LATENCY:
1024 pi[count].preference_value = (float) va_arg (ap, double);
1033 GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head, ph->pending_tail, p);
1037 /* end of ats_api_performance.c */