2 This file is part of GNUnet.
3 Copyright (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"
31 #define LOG(kind,...) GNUNET_log_from(kind, "ats-performance-api", __VA_ARGS__)
35 * Message in linked list we should send to the ATS service. The
36 * actual binary message follows this struct.
44 struct PendingMessage *next;
49 struct PendingMessage *prev;
52 * Size of the message.
57 * Is this the 'ATS_START' message?
64 * Linked list of pending reservations.
66 struct GNUNET_ATS_ReservationContext
72 struct GNUNET_ATS_ReservationContext *next;
77 struct GNUNET_ATS_ReservationContext *prev;
82 struct GNUNET_PeerIdentity peer;
90 * Function to call on result.
92 GNUNET_ATS_ReservationCallback rcb;
100 * Do we need to undo this reservation if it succeeded? Set to
101 * #GNUNET_YES if a reservation is cancelled. (at that point, 'info'
102 * is also set to NULL; however, info will ALSO be NULL for the
103 * reservation context that is created to undo the original request,
104 * so 'info' being NULL cannot be used to check if undo is
112 * Linked list of pending reservations.
114 struct GNUNET_ATS_AddressListHandle
120 struct GNUNET_ATS_AddressListHandle *next;
125 struct GNUNET_ATS_AddressListHandle *prev;
130 struct GNUNET_ATS_PerformanceHandle *ph;
135 GNUNET_ATS_AddressInformationCallback cb;
138 * Callback closure for @e cb
145 struct GNUNET_PeerIdentity peer;
148 * Return all or specific peer only
153 * Return all or used address only
158 * Request multiplexing
165 * ATS Handle to obtain and/or modify performance information.
167 struct GNUNET_ATS_PerformanceHandle
173 const struct GNUNET_CONFIGURATION_Handle *cfg;
176 * Callback to invoke when an address has performance changes.
178 GNUNET_ATS_AddressInformationCallback addr_info_cb;
181 * Closure for @e addr_info_cb.
183 void *addr_info_cb_cls;
186 * Connection to ATS service.
188 struct GNUNET_CLIENT_Connection *client;
191 * Head of list of messages for the ATS service.
193 struct PendingMessage *pending_head;
196 * Tail of list of messages for the ATS service
198 struct PendingMessage *pending_tail;
201 * Head of linked list of pending reservation requests.
203 struct GNUNET_ATS_ReservationContext *reservation_head;
206 * Tail of linked list of pending reservation requests.
208 struct GNUNET_ATS_ReservationContext *reservation_tail;
211 * Head of linked list of pending address list requests.
213 struct GNUNET_ATS_AddressListHandle *addresslist_head;
216 * Tail of linked list of pending address list requests.
218 struct GNUNET_ATS_AddressListHandle *addresslist_tail;
221 * Current request for transmission to ATS.
223 struct GNUNET_CLIENT_TransmitHandle *th;
226 * Task to trigger reconnect.
228 struct GNUNET_SCHEDULER_Task *task;
231 * Reconnect backoff delay.
233 struct GNUNET_TIME_Relative backoff;
236 * Monitor request multiplexing
241 * Request multiplexing
246 * Is the receive loop active?
252 * Re-establish the connection to the ATS service.
254 * @param ph handle to use to re-connect.
257 reconnect (struct GNUNET_ATS_PerformanceHandle *ph);
261 * Re-establish the connection to the ATS service.
263 * @param cls handle to use to re-connect.
264 * @param tc scheduler context
267 reconnect_task (void *cls,
268 const struct GNUNET_SCHEDULER_TaskContext *tc)
270 struct GNUNET_ATS_PerformanceHandle *ph = cls;
278 * Transmit messages from the message queue to the service
279 * (if there are any, and if we are not already trying).
281 * @param ph handle to use
284 do_transmit (struct GNUNET_ATS_PerformanceHandle *ph);
288 * Type of a function to call when we receive a message
291 * @param cls the `struct GNUNET_ATS_SchedulingHandle`
292 * @param msg message received, NULL on timeout or fatal error
295 process_ats_message (void *cls,
296 const struct GNUNET_MessageHeader *msg);
300 * We can now transmit a message to ATS. Do it.
302 * @param cls the `struct GNUNET_ATS_PerformanceHandle`
303 * @param size number of bytes we can transmit to ATS
304 * @param buf where to copy the messages
305 * @return number of bytes copied into @a buf
308 transmit_message_to_ats (void *cls,
312 struct GNUNET_ATS_PerformanceHandle *ph = cls;
313 struct PendingMessage *p;
320 while ((NULL != (p = ph->pending_head)) && (p->size <= size))
322 memcpy (&cbuf[ret], &p[1], p->size);
325 GNUNET_CONTAINER_DLL_remove (ph->pending_head,
331 if (GNUNET_NO == ph->in_receive)
333 ph->in_receive = GNUNET_YES;
334 GNUNET_CLIENT_receive (ph->client,
335 &process_ats_message,
337 GNUNET_TIME_UNIT_FOREVER_REL);
344 * Transmit messages from the message queue to the service
345 * (if there are any, and if we are not already trying).
347 * @param ph handle to use
350 do_transmit (struct GNUNET_ATS_PerformanceHandle *ph)
352 struct PendingMessage *p;
356 if (NULL == (p = ph->pending_head))
358 if (NULL == ph->client)
359 return; /* currently reconnecting */
360 ph->th = GNUNET_CLIENT_notify_transmit_ready (ph->client,
362 GNUNET_TIME_UNIT_FOREVER_REL,
364 &transmit_message_to_ats, ph);
369 * We received a peer information message. Validate and process it.
371 * @param ph our context with the callback
372 * @param msg the message
373 * @return #GNUNET_OK if the message was well-formed
376 process_pi_message (struct GNUNET_ATS_PerformanceHandle *ph,
377 const struct GNUNET_MessageHeader *msg)
379 const struct PeerInformationMessage *pi;
380 const char *plugin_address;
381 const char *plugin_name;
382 struct GNUNET_HELLO_Address address;
383 uint16_t plugin_address_length;
384 uint16_t plugin_name_length;
386 struct GNUNET_ATS_Properties prop;
388 if (ntohs (msg->size) < sizeof(struct PeerInformationMessage))
391 return GNUNET_SYSERR;
393 pi = (const struct PeerInformationMessage *) msg;
394 plugin_address_length = ntohs (pi->address_length);
395 plugin_name_length = ntohs (pi->plugin_name_length);
396 addr_active = (int) ntohl (pi->address_active);
397 plugin_address = (const char *) &pi[1];
398 plugin_name = &plugin_address[plugin_address_length];
399 if ((plugin_address_length + plugin_name_length
400 + sizeof(struct PeerInformationMessage) != ntohs (msg->size))
401 || (plugin_name[plugin_name_length - 1] != '\0'))
404 return GNUNET_SYSERR;
407 if (NULL != ph->addr_info_cb)
409 GNUNET_ATS_properties_ntoh (&prop,
411 address.peer = pi->peer;
412 address.address = plugin_address;
413 address.address_length = plugin_address_length;
414 address.transport_name = plugin_name;
415 ph->addr_info_cb (ph->addr_info_cb_cls,
427 * We received a reservation result message. Validate and process it.
429 * @param ph our context with the callback
430 * @param msg the message
431 * @return #GNUNET_OK if the message was well-formed
434 process_rr_message (struct GNUNET_ATS_PerformanceHandle *ph,
435 const struct GNUNET_MessageHeader *msg)
437 const struct ReservationResultMessage *rr;
438 struct GNUNET_ATS_ReservationContext *rc;
441 if (ntohs (msg->size) < sizeof(struct ReservationResultMessage))
444 return GNUNET_SYSERR;
446 rr = (const struct ReservationResultMessage *) msg;
447 amount = ntohl (rr->amount);
448 rc = ph->reservation_head;
449 if (0 != memcmp (&rr->peer, &rc->peer, sizeof(struct GNUNET_PeerIdentity)))
452 return GNUNET_SYSERR;
454 GNUNET_CONTAINER_DLL_remove (ph->reservation_head,
455 ph->reservation_tail,
457 if ( (0 == amount) ||
460 /* tell client if not cancelled */
461 if (rc->rcb != NULL )
462 rc->rcb (rc->rcb_cls,
465 GNUNET_TIME_relative_ntoh (rr->res_delay));
469 /* amount non-zero, but client cancelled, consider undo! */
470 if (GNUNET_YES != rc->undo)
473 return GNUNET_OK; /* do not try to undo failed undos or negative amounts */
476 (void) GNUNET_ATS_reserve_bandwidth (ph,
485 * We received a PeerInformationMessage. Validate and process it.
487 * @param ph our context with the callback
488 * @param msg the message
489 * @return #GNUNET_OK if the message was well-formed
492 process_ar_message (struct GNUNET_ATS_PerformanceHandle *ph,
493 const struct GNUNET_MessageHeader *msg)
495 const struct PeerInformationMessage *pi;
496 struct GNUNET_ATS_AddressListHandle *alh;
497 struct GNUNET_ATS_AddressListHandle *next;
498 const char *plugin_address;
499 const char *plugin_name;
500 struct GNUNET_HELLO_Address address;
501 struct GNUNET_PeerIdentity allzeros;
502 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_zero;
503 struct GNUNET_ATS_Properties prop;
504 uint16_t plugin_address_length;
505 uint16_t plugin_name_length;
509 if (ntohs (msg->size) < sizeof(struct PeerInformationMessage))
512 return GNUNET_SYSERR;
514 pi = (const struct PeerInformationMessage *) msg;
516 active = ntohl (pi->address_active);
517 plugin_address_length = ntohs (pi->address_length);
518 plugin_name_length = ntohs (pi->plugin_name_length);
519 plugin_address = (const char *) &pi[1];
520 plugin_name = &plugin_address[plugin_address_length];
521 if ( (plugin_address_length + plugin_name_length
522 + sizeof (struct PeerInformationMessage) != ntohs (msg->size)) ||
523 (plugin_name[plugin_name_length - 1] != '\0') )
526 return GNUNET_SYSERR;
528 LOG (GNUNET_ERROR_TYPE_DEBUG,
529 "Received ATS_ADDRESSLIST_RESPONSE message for peer %s and plugin %s\n",
530 GNUNET_i2s (&pi->peer),
533 next = ph->addresslist_head;
534 while (NULL != (alh = next))
543 return GNUNET_SYSERR;
546 memset (&allzeros, '\0', sizeof (allzeros));
547 if ( (0 == memcmp (&allzeros, &pi->peer, sizeof(allzeros))) &&
548 (0 == plugin_name_length) &&
549 (0 == plugin_address_length) )
552 LOG (GNUNET_ERROR_TYPE_DEBUG,
553 "Received last message for ATS_ADDRESSLIST_RESPONSE\n");
554 bandwidth_zero.value__ = htonl (0);
555 GNUNET_CONTAINER_DLL_remove (ph->addresslist_head,
556 ph->addresslist_tail,
559 alh->cb (alh->cb_cls,
569 address.peer = pi->peer;
570 address.address = plugin_address;
571 address.address_length = plugin_address_length;
572 address.transport_name = plugin_name;
573 if ( ( (GNUNET_YES == alh->all_addresses) ||
574 (GNUNET_YES == active) ) &&
577 GNUNET_ATS_properties_ntoh (&prop,
579 alh->cb (alh->cb_cls,
591 * Type of a function to call when we receive a message
594 * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
595 * @param msg message received, NULL on timeout or fatal error
598 process_ats_message (void *cls,
599 const struct GNUNET_MessageHeader *msg)
601 struct GNUNET_ATS_PerformanceHandle *ph = cls;
605 switch (ntohs (msg->type))
607 case GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION:
608 if (GNUNET_OK != process_pi_message (ph, msg))
614 case GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT:
615 if (GNUNET_OK != process_rr_message (ph, msg))
621 case GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE:
622 if (GNUNET_OK != process_ar_message (ph, msg))
632 ph->backoff = GNUNET_TIME_UNIT_ZERO;
633 GNUNET_CLIENT_receive (ph->client,
634 &process_ats_message,
636 GNUNET_TIME_UNIT_FOREVER_REL);
640 LOG (GNUNET_ERROR_TYPE_DEBUG,
644 GNUNET_CLIENT_notify_transmit_ready_cancel (ph->th);
647 if (NULL != ph->client)
649 GNUNET_CLIENT_disconnect (ph->client);
651 ph->in_receive = GNUNET_NO;
652 if (NULL != ph->addr_info_cb)
654 /* Indicate reconnect */
655 ph->addr_info_cb (ph->addr_info_cb_cls,
658 GNUNET_BANDWIDTH_value_init (0),
659 GNUNET_BANDWIDTH_value_init (0),
663 ph->backoff = GNUNET_TIME_STD_BACKOFF (ph->backoff);
664 ph->task = GNUNET_SCHEDULER_add_delayed (ph->backoff,
671 * Re-establish the connection to the ATS service.
673 * @param ph handle to use to re-connect.
676 reconnect (struct GNUNET_ATS_PerformanceHandle *ph)
678 struct PendingMessage *p;
679 struct ClientStartMessage *init;
681 GNUNET_assert (NULL == ph->client);
682 ph->client = GNUNET_CLIENT_connect ("ats",
684 GNUNET_assert (NULL != ph->client);
685 if ((NULL == (p = ph->pending_head)) || (GNUNET_YES != p->is_init))
687 p = GNUNET_malloc (sizeof (struct PendingMessage) +
688 sizeof (struct ClientStartMessage));
689 p->size = sizeof(struct ClientStartMessage);
690 p->is_init = GNUNET_YES;
691 init = (struct ClientStartMessage *) &p[1];
692 init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START);
693 init->header.size = htons (sizeof(struct ClientStartMessage));
694 init->start_flag = htonl ( (NULL == ph->addr_info_cb)
695 ? START_FLAG_PERFORMANCE_NO_PIC
696 : START_FLAG_PERFORMANCE_WITH_PIC);
697 GNUNET_CONTAINER_DLL_insert (ph->pending_head,
706 * Get handle to access performance API of the ATS subsystem.
708 * @param cfg configuration to use
709 * @param addr_info_cb callback called when performance characteristics for
711 * @param addr_info_cb_cls closure for @a addr_info_cb
712 * @return ats performance context
714 struct GNUNET_ATS_PerformanceHandle *
715 GNUNET_ATS_performance_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
716 GNUNET_ATS_AddressInformationCallback addr_info_cb,
717 void *addr_info_cb_cls)
719 struct GNUNET_ATS_PerformanceHandle *ph;
721 ph = GNUNET_new (struct GNUNET_ATS_PerformanceHandle);
723 ph->addr_info_cb = addr_info_cb;
724 ph->addr_info_cb_cls = addr_info_cb_cls;
732 * Client is done using the ATS performance subsystem, release resources.
737 GNUNET_ATS_performance_done (struct GNUNET_ATS_PerformanceHandle *ph)
739 struct PendingMessage *p;
740 struct GNUNET_ATS_ReservationContext *rc;
741 struct GNUNET_ATS_AddressListHandle *alh;
743 while (NULL != (p = ph->pending_head))
745 GNUNET_CONTAINER_DLL_remove (ph->pending_head,
750 while (NULL != (alh = ph->addresslist_head))
752 GNUNET_CONTAINER_DLL_remove (ph->addresslist_head,
753 ph->addresslist_tail,
757 while (NULL != (rc = ph->reservation_head))
759 GNUNET_CONTAINER_DLL_remove (ph->reservation_head,
760 ph->reservation_tail,
762 GNUNET_break (NULL == rc->rcb);
766 if (NULL != ph->task)
768 GNUNET_SCHEDULER_cancel (ph->task);
771 if (NULL != ph->client)
773 GNUNET_CLIENT_disconnect (ph->client);
781 * Reserve inbound bandwidth from the given peer. ATS will look at
782 * the current amount of traffic we receive from the peer and ensure
783 * that the peer could add 'amount' of data to its stream.
785 * @param ph performance handle
786 * @param peer identifies the peer
787 * @param amount reserve N bytes for receiving, negative
788 * amounts can be used to undo a (recent) reservation;
789 * @param rcb function to call with the resulting reservation information
790 * @param rcb_cls closure for @a rcb
791 * @return NULL on error
792 * @deprecated will be replaced soon
794 struct GNUNET_ATS_ReservationContext *
795 GNUNET_ATS_reserve_bandwidth (struct GNUNET_ATS_PerformanceHandle *ph,
796 const struct GNUNET_PeerIdentity *peer,
798 GNUNET_ATS_ReservationCallback rcb, void *rcb_cls)
800 struct GNUNET_ATS_ReservationContext *rc;
801 struct PendingMessage *p;
802 struct ReservationRequestMessage *m;
804 rc = GNUNET_new (struct GNUNET_ATS_ReservationContext);
808 rc->rcb_cls = rcb_cls;
809 if ( (NULL != rcb) &&
811 rc->undo = GNUNET_YES;
812 GNUNET_CONTAINER_DLL_insert_tail (ph->reservation_head,
813 ph->reservation_tail,
816 p = GNUNET_malloc (sizeof (struct PendingMessage) +
817 sizeof (struct ReservationRequestMessage));
818 p->size = sizeof(struct ReservationRequestMessage);
819 p->is_init = GNUNET_NO;
820 m = (struct ReservationRequestMessage *) &p[1];
821 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST);
822 m->header.size = htons (sizeof(struct ReservationRequestMessage));
823 m->amount = htonl (amount);
825 GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head,
834 * Cancel request for reserving bandwidth.
836 * @param rc context returned by the original GNUNET_ATS_reserve_bandwidth call
839 GNUNET_ATS_reserve_bandwidth_cancel (struct GNUNET_ATS_ReservationContext *rc)
846 * Get information about addresses known to the ATS subsystem.
848 * @param handle the performance handle to use
849 * @param peer peer idm can be NULL for all peers
850 * @param all #GNUNET_YES to get information about all addresses or #GNUNET_NO to
851 * get only address currently used
852 * @param infocb callback to call with the addresses,
853 * will callback with address == NULL when done
854 * @param infocb_cls closure for @a infocb
855 * @return ats performance context
857 struct GNUNET_ATS_AddressListHandle*
858 GNUNET_ATS_performance_list_addresses (struct GNUNET_ATS_PerformanceHandle *handle,
859 const struct GNUNET_PeerIdentity *peer,
861 GNUNET_ATS_AddressInformationCallback infocb,
864 struct GNUNET_ATS_AddressListHandle *alh;
865 struct PendingMessage *p;
866 struct AddressListRequestMessage *m;
870 alh = GNUNET_new (struct GNUNET_ATS_AddressListHandle);
871 alh->id = handle->id;
874 alh->cb_cls = infocb_cls;
876 alh->all_addresses = all;
879 alh->all_peers = GNUNET_YES;
883 alh->all_peers = GNUNET_NO;
886 GNUNET_CONTAINER_DLL_insert (handle->addresslist_head,
887 handle->addresslist_tail,
890 p = GNUNET_malloc (sizeof (struct PendingMessage) +
891 sizeof (struct AddressListRequestMessage));
892 p->size = sizeof (struct AddressListRequestMessage);
893 m = (struct AddressListRequestMessage *) &p[1];
894 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_REQUEST);
895 m->header.size = htons (sizeof(struct AddressListRequestMessage));
896 m->all = htonl (all);
897 m->id = htonl (alh->id);
900 GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head,
901 handle->pending_tail,
903 do_transmit (handle);
910 * Cancel a pending address listing operation
912 * @param handle the handle of the request to cancel
915 GNUNET_ATS_performance_list_addresses_cancel (struct GNUNET_ATS_AddressListHandle *handle)
917 GNUNET_CONTAINER_DLL_remove (handle->ph->addresslist_head,
918 handle->ph->addresslist_tail,
920 GNUNET_free (handle);
925 * Convert a `enum GNUNET_ATS_PreferenceType` to a string
927 * @param type the preference type
928 * @return a string or NULL if invalid
931 GNUNET_ATS_print_preference_type (uint32_t type)
933 const char *prefs[] = GNUNET_ATS_PreferenceTypeString;
935 if (type < GNUNET_ATS_PREFERENCE_END)
942 * Change preferences for the given peer. Preference changes are forgotten if peers
945 * @param ph performance handle
946 * @param peer identifies the peer
947 * @param ... #GNUNET_ATS_PREFERENCE_END-terminated specification of the desired changes
950 GNUNET_ATS_performance_change_preference (struct GNUNET_ATS_PerformanceHandle *ph,
951 const struct GNUNET_PeerIdentity *peer, ...)
953 struct PendingMessage *p;
954 struct ChangePreferenceMessage *m;
957 struct PreferenceInformation *pi;
959 enum GNUNET_ATS_PreferenceKind kind;
963 while (GNUNET_ATS_PREFERENCE_END !=
964 (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind) ))
968 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
970 (void) va_arg (ap, double);
972 case GNUNET_ATS_PREFERENCE_LATENCY:
974 (void) va_arg (ap, double);
981 msize = count * sizeof(struct PreferenceInformation)
982 + sizeof(struct ChangePreferenceMessage);
983 p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
985 p->is_init = GNUNET_NO;
986 m = (struct ChangePreferenceMessage *) &p[1];
987 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE);
988 m->header.size = htons (msize);
989 m->num_preferences = htonl (count);
991 pi = (struct PreferenceInformation *) &m[1];
994 while (GNUNET_ATS_PREFERENCE_END != (kind =
995 va_arg (ap, enum GNUNET_ATS_PreferenceKind) ))
997 pi[count].preference_kind = htonl (kind);
1000 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
1001 pi[count].preference_value = (float) va_arg (ap, double);
1005 case GNUNET_ATS_PREFERENCE_LATENCY:
1006 pi[count].preference_value = (float) va_arg (ap, double);
1015 GNUNET_CONTAINER_DLL_insert_tail(ph->pending_head, ph->pending_tail, p);
1021 * Send feedback to ATS on how good a the requirements for a peer and a
1022 * preference is satisfied by ATS
1024 * @param ph performance handle
1025 * @param scope the time interval this valid for: [now - scope .. now]
1026 * @param peer identifies the peer
1027 * @param ... #GNUNET_ATS_PREFERENCE_END-terminated specification of the desired changes
1030 GNUNET_ATS_performance_give_feedback (struct GNUNET_ATS_PerformanceHandle *ph,
1031 const struct GNUNET_PeerIdentity *peer,
1032 const struct GNUNET_TIME_Relative scope, ...)
1034 struct PendingMessage *p;
1035 struct FeedbackPreferenceMessage *m;
1038 struct PreferenceInformation *pi;
1040 enum GNUNET_ATS_PreferenceKind kind;
1043 va_start(ap, scope);
1044 while (GNUNET_ATS_PREFERENCE_END !=
1045 (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind) ))
1049 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
1051 (void) va_arg (ap, double);
1053 case GNUNET_ATS_PREFERENCE_LATENCY:
1055 (void) va_arg (ap, double);
1062 msize = count * sizeof(struct PreferenceInformation)
1063 + sizeof(struct FeedbackPreferenceMessage);
1064 p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
1066 p->is_init = GNUNET_NO;
1067 m = (struct FeedbackPreferenceMessage *) &p[1];
1068 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_FEEDBACK);
1069 m->header.size = htons (msize);
1070 m->scope = GNUNET_TIME_relative_hton (scope);
1071 m->num_feedback = htonl (count);
1073 pi = (struct PreferenceInformation *) &m[1];
1075 va_start(ap, scope);
1076 while (GNUNET_ATS_PREFERENCE_END != (kind =
1077 va_arg (ap, enum GNUNET_ATS_PreferenceKind) ))
1079 pi[count].preference_kind = htonl (kind);
1082 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
1083 pi[count].preference_value = (float) va_arg (ap, double);
1087 case GNUNET_ATS_PREFERENCE_LATENCY:
1088 pi[count].preference_value = (float) va_arg (ap, double);
1097 GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head,
1103 /* end of ats_api_performance.c */