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"
31 * Message in linked list we should send to the ATS service. The
32 * actual binary message follows this struct.
40 struct PendingMessage *next;
45 struct PendingMessage *prev;
48 * Size of the message.
53 * Is this the 'ATS_START' message?
60 * Linked list of pending reservations.
62 struct GNUNET_ATS_ReservationContext
68 struct GNUNET_ATS_ReservationContext *next;
73 struct GNUNET_ATS_ReservationContext *prev;
78 struct GNUNET_PeerIdentity peer;
86 * Function to call on result.
88 GNUNET_ATS_ReservationCallback rcb;
96 * Do we need to undo this reservation if it succeeded? Set to
97 * #GNUNET_YES if a reservation is cancelled. (at that point, 'info'
98 * is also set to NULL; however, info will ALSO be NULL for the
99 * reservation context that is created to undo the original request,
100 * so 'info' being NULL cannot be used to check if undo is
108 * Linked list of pending reservations.
110 struct GNUNET_ATS_AddressListHandle
116 struct GNUNET_ATS_AddressListHandle *next;
121 struct GNUNET_ATS_AddressListHandle *prev;
126 struct GNUNET_ATS_PerformanceHandle *ph;
131 GNUNET_ATS_AddressInformationCallback cb;
141 struct GNUNET_PeerIdentity peer;
144 * Return all or specific peer only
149 * Return all or used address only
154 * Request multiplexing
161 * ATS Handle to obtain and/or modify performance information.
163 struct GNUNET_ATS_PerformanceHandle
169 const struct GNUNET_CONFIGURATION_Handle *cfg;
172 * Callback to invoke when an address has performance changes.
174 GNUNET_ATS_AddressInformationCallback addr_info_cb;
177 * Closure for @e addr_info_cb.
179 void *addr_info_cb_cls;
182 * Connection to ATS service.
184 struct GNUNET_CLIENT_Connection *client;
187 * Head of list of messages for the ATS service.
189 struct PendingMessage *pending_head;
192 * Tail of list of messages for the ATS service
194 struct PendingMessage *pending_tail;
197 * Head of linked list of pending reservation requests.
199 struct GNUNET_ATS_ReservationContext *reservation_head;
202 * Tail of linked list of pending reservation requests.
204 struct GNUNET_ATS_ReservationContext *reservation_tail;
207 * Head of linked list of pending address list requests.
209 struct GNUNET_ATS_AddressListHandle *addresslist_head;
212 * Tail of linked list of pending address list requests.
214 struct GNUNET_ATS_AddressListHandle *addresslist_tail;
217 * Current request for transmission to ATS.
219 struct GNUNET_CLIENT_TransmitHandle *th;
222 * Task to trigger reconnect.
224 GNUNET_SCHEDULER_TaskIdentifier task;
227 * Monitor request multiplexing
232 * Request multiplexing
238 * Re-establish the connection to the ATS service.
240 * @param ph handle to use to re-connect.
243 reconnect (struct GNUNET_ATS_PerformanceHandle *ph);
247 * Re-establish the connection to the ATS service.
249 * @param cls handle to use to re-connect.
250 * @param tc scheduler context
253 reconnect_task (void *cls,
254 const struct GNUNET_SCHEDULER_TaskContext *tc)
256 struct GNUNET_ATS_PerformanceHandle *ph = cls;
258 ph->task = GNUNET_SCHEDULER_NO_TASK;
264 * Transmit messages from the message queue to the service
265 * (if there are any, and if we are not already trying).
267 * @param ph handle to use
270 do_transmit (struct GNUNET_ATS_PerformanceHandle *ph);
274 * Type of a function to call when we receive a message
277 * @param cls the `struct GNUNET_ATS_SchedulingHandle`
278 * @param msg message received, NULL on timeout or fatal error
281 process_ats_message (void *cls,
282 const struct GNUNET_MessageHeader *msg);
286 * We can now transmit a message to ATS. Do it.
288 * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
289 * @param size number of bytes we can transmit to ATS
290 * @param buf where to copy the messages
291 * @return number of bytes copied into buf
294 transmit_message_to_ats (void *cls, size_t size, void *buf)
296 struct GNUNET_ATS_PerformanceHandle *ph = cls;
297 struct PendingMessage *p;
304 while ((NULL != (p = ph->pending_head)) && (p->size <= size))
306 memcpy (&cbuf[ret], &p[1], p->size);
309 GNUNET_CONTAINER_DLL_remove(ph->pending_head, ph->pending_tail, p);
318 * Transmit messages from the message queue to the service
319 * (if there are any, and if we are not already trying).
321 * @param ph handle to use
324 do_transmit (struct GNUNET_ATS_PerformanceHandle *ph)
326 struct PendingMessage *p;
330 if (NULL == (p = ph->pending_head))
332 if (NULL == ph->client)
333 return; /* currently reconnecting */
334 ph->th = GNUNET_CLIENT_notify_transmit_ready (ph->client, p->size,
335 GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &transmit_message_to_ats, ph);
340 * We received a peer information message. Validate and process it.
342 * @param ph our context with the callback
343 * @param msg the message
344 * @return #GNUNET_OK if the message was well-formed
347 process_pi_message (struct GNUNET_ATS_PerformanceHandle *ph,
348 const struct GNUNET_MessageHeader *msg)
350 const struct PeerInformationMessage *pi;
351 const struct GNUNET_ATS_Information *atsi;
352 const char *plugin_address;
353 const char *plugin_name;
354 struct GNUNET_HELLO_Address address;
355 uint16_t plugin_address_length;
356 uint16_t plugin_name_length;
360 if (ntohs (msg->size) < sizeof(struct PeerInformationMessage))
363 return GNUNET_SYSERR;
366 pi = (const struct PeerInformationMessage *) msg;
367 ats_count = ntohl (pi->ats_count);
368 plugin_address_length = ntohs (pi->address_length);
369 plugin_name_length = ntohs (pi->plugin_name_length);
370 addr_active = (int) ntohl (pi->address_active);
371 atsi = (const struct GNUNET_ATS_Information *) &pi[1];
372 plugin_address = (const char *) &atsi[ats_count];
373 plugin_name = &plugin_address[plugin_address_length];
374 if ((plugin_address_length + plugin_name_length
375 + ats_count * sizeof(struct GNUNET_ATS_Information)
376 + sizeof(struct PeerInformationMessage) != ntohs (msg->size))
378 > GNUNET_SERVER_MAX_MESSAGE_SIZE
379 / sizeof(struct GNUNET_ATS_Information))
380 || (plugin_name[plugin_name_length - 1] != '\0'))
383 return GNUNET_SYSERR;
386 if (NULL != ph->addr_info_cb)
388 address.peer = pi->peer;
389 address.address = plugin_address;
390 address.address_length = plugin_address_length;
391 address.transport_name = plugin_name;
392 ph->addr_info_cb (ph->addr_info_cb_cls,
404 * We received a reservation result message. Validate and process it.
406 * @param ph our context with the callback
407 * @param msg the message
408 * @return #GNUNET_OK if the message was well-formed
411 process_rr_message (struct GNUNET_ATS_PerformanceHandle *ph,
412 const struct GNUNET_MessageHeader *msg)
414 const struct ReservationResultMessage *rr;
415 struct GNUNET_ATS_ReservationContext *rc;
418 if (ntohs (msg->size) < sizeof(struct ReservationResultMessage))
421 return GNUNET_SYSERR;
423 rr = (const struct ReservationResultMessage *) msg;
424 amount = ntohl (rr->amount);
425 rc = ph->reservation_head;
426 if (0 != memcmp (&rr->peer, &rc->peer, sizeof(struct GNUNET_PeerIdentity)))
429 return GNUNET_SYSERR;
431 GNUNET_CONTAINER_DLL_remove(ph->reservation_head, ph->reservation_tail, rc);
432 if ((amount == 0) || (rc->rcb != NULL ))
434 /* tell client if not cancelled */
435 if (rc->rcb != NULL )
436 rc->rcb (rc->rcb_cls, &rr->peer, amount,
437 GNUNET_TIME_relative_ntoh (rr->res_delay));
441 /* amount non-zero, but client cancelled, consider undo! */
442 if (GNUNET_YES != rc->undo)
445 return GNUNET_OK; /* do not try to undo failed undos or negative amounts */
448 (void) GNUNET_ATS_reserve_bandwidth (ph, &rr->peer, -amount, NULL, NULL );
454 * We received a reservation result message. Validate and process it.
456 * @param ph our context with the callback
457 * @param msg the message
458 * @return #GNUNET_OK if the message was well-formed
461 process_ar_message (struct GNUNET_ATS_PerformanceHandle *ph,
462 const struct GNUNET_MessageHeader *msg)
464 const struct PeerInformationMessage *pi;
465 struct GNUNET_ATS_AddressListHandle *alh;
466 struct GNUNET_ATS_AddressListHandle *next;
467 const struct GNUNET_ATS_Information *atsi;
468 const char *plugin_address;
469 const char *plugin_name;
470 struct GNUNET_HELLO_Address address;
471 struct GNUNET_PeerIdentity allzeros;
472 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_zero;
473 uint16_t plugin_address_length;
474 uint16_t plugin_name_length;
479 if (ntohs (msg->size) < sizeof(struct PeerInformationMessage))
482 return GNUNET_SYSERR;
484 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
485 _("Received %s message\n"),
486 "ATS_ADDRESSLIST_RESPONSE");
488 pi = (const struct PeerInformationMessage *) msg;
490 ats_count = ntohl (pi->ats_count);
491 active = ntohl (pi->address_active);
492 plugin_address_length = ntohs (pi->address_length);
493 plugin_name_length = ntohs (pi->plugin_name_length);
494 atsi = (const struct GNUNET_ATS_Information *) &pi[1];
495 plugin_address = (const char *) &atsi[ats_count];
496 plugin_name = &plugin_address[plugin_address_length];
497 if ((plugin_address_length + plugin_name_length
498 + ats_count * sizeof(struct GNUNET_ATS_Information)
499 + sizeof(struct PeerInformationMessage) != ntohs (msg->size))
501 > GNUNET_SERVER_MAX_MESSAGE_SIZE
502 / sizeof(struct GNUNET_ATS_Information))
503 || (plugin_name[plugin_name_length - 1] != '\0'))
506 return GNUNET_SYSERR;
509 next = ph->addresslist_head;
510 while (NULL != (alh = next))
519 return GNUNET_SYSERR;
522 memset (&allzeros, '\0', sizeof(allzeros));
523 if ((0 == memcmp (&allzeros, &pi->peer, sizeof(allzeros)))
524 && (0 == plugin_name_length) && (0 == plugin_address_length)
528 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Received last message for %s \n"),
529 "ATS_ADDRESSLIST_RESPONSE");
530 bandwidth_zero.value__ = htonl (0);
532 alh->cb (ph->addr_info_cb_cls, NULL, GNUNET_NO, bandwidth_zero,
533 bandwidth_zero, NULL, 0);
534 GNUNET_CONTAINER_DLL_remove(ph->addresslist_head, ph->addresslist_tail,
540 address.peer = pi->peer;
541 address.address = plugin_address;
542 address.address_length = plugin_address_length;
543 address.transport_name = plugin_name;
545 if ((GNUNET_YES == alh->all_addresses) || (GNUNET_YES == active))
548 alh->cb (ph->addr_info_cb_cls, &address, active, pi->bandwidth_out,
549 pi->bandwidth_in, atsi, ats_count);
556 * Type of a function to call when we receive a message
559 * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
560 * @param msg message received, NULL on timeout or fatal error
563 process_ats_message (void *cls,
564 const struct GNUNET_MessageHeader *msg)
566 struct GNUNET_ATS_PerformanceHandle *ph = cls;
570 switch (ntohs (msg->type))
572 case GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION:
573 if (GNUNET_OK != process_pi_message (ph, msg))
576 case GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT:
577 if (GNUNET_OK != process_rr_message (ph, msg))
580 case GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE:
581 if (GNUNET_OK != process_ar_message (ph, msg))
588 GNUNET_CLIENT_receive (ph->client, &process_ats_message, ph,
589 GNUNET_TIME_UNIT_FOREVER_REL);
595 GNUNET_CLIENT_notify_transmit_ready_cancel (ph->th);
598 GNUNET_CLIENT_disconnect (ph->client);
600 if (NULL != ph->addr_info_cb)
602 /* Indicate reconnect */
603 ph->addr_info_cb (ph->addr_info_cb_cls, NULL, GNUNET_NO,
604 GNUNET_BANDWIDTH_value_init (0),
605 GNUNET_BANDWIDTH_value_init(0),
608 ph->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
609 &reconnect_task, ph);
614 * Re-establish the connection to the ATS service.
616 * @param ph handle to use to re-connect.
619 reconnect (struct GNUNET_ATS_PerformanceHandle *ph)
621 struct PendingMessage *p;
622 struct ClientStartMessage *init;
624 GNUNET_assert(NULL == ph->client);
625 ph->client = GNUNET_CLIENT_connect ("ats", ph->cfg);
626 GNUNET_assert(NULL != ph->client);
627 GNUNET_CLIENT_receive (ph->client, &process_ats_message, ph,
628 GNUNET_TIME_UNIT_FOREVER_REL);
629 if ((NULL == (p = ph->pending_head)) || (GNUNET_YES != p->is_init))
631 p = GNUNET_malloc (sizeof (struct PendingMessage) +
632 sizeof (struct ClientStartMessage));
633 p->size = sizeof(struct ClientStartMessage);
634 p->is_init = GNUNET_YES;
635 init = (struct ClientStartMessage *) &p[1];
636 init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START);
637 init->header.size = htons (sizeof(struct ClientStartMessage));
638 init->start_flag = htonl (
639 (NULL == ph->addr_info_cb) ?
640 START_FLAG_PERFORMANCE_NO_PIC : START_FLAG_PERFORMANCE_WITH_PIC);
641 GNUNET_CONTAINER_DLL_insert(ph->pending_head, ph->pending_tail, p);
648 * Get handle to access performance API of the ATS subsystem.
650 * @param cfg configuration to use
651 * @param addr_info_cb callback called when performance characteristics for
653 * @param addr_info_cb_cls closure for @a addr_info_cb
654 * @return ats performance context
656 struct GNUNET_ATS_PerformanceHandle *
657 GNUNET_ATS_performance_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
658 GNUNET_ATS_AddressInformationCallback addr_info_cb,
659 void *addr_info_cb_cls)
661 struct GNUNET_ATS_PerformanceHandle *ph;
663 ph = GNUNET_new (struct GNUNET_ATS_PerformanceHandle);
665 ph->addr_info_cb = addr_info_cb;
666 ph->addr_info_cb_cls = addr_info_cb_cls;
674 * Client is done using the ATS performance subsystem, release resources.
679 GNUNET_ATS_performance_done (struct GNUNET_ATS_PerformanceHandle *ph)
681 struct PendingMessage *p;
682 struct GNUNET_ATS_ReservationContext *rc;
683 struct GNUNET_ATS_AddressListHandle *alh;
685 while (NULL != (p = ph->pending_head))
687 GNUNET_CONTAINER_DLL_remove(ph->pending_head, ph->pending_tail, p);
690 while (NULL != (alh = ph->addresslist_head))
692 GNUNET_CONTAINER_DLL_remove(ph->addresslist_head, ph->addresslist_tail,
696 while (NULL != (rc = ph->reservation_head))
698 GNUNET_CONTAINER_DLL_remove(ph->reservation_head, ph->reservation_tail, rc);
699 GNUNET_break(NULL == rc->rcb);
703 if (GNUNET_SCHEDULER_NO_TASK != ph->task)
705 GNUNET_SCHEDULER_cancel (ph->task);
706 ph->task = GNUNET_SCHEDULER_NO_TASK;
708 if (NULL != ph->client)
710 GNUNET_CLIENT_disconnect (ph->client);
718 * Reserve inbound bandwidth from the given peer. ATS will look at
719 * the current amount of traffic we receive from the peer and ensure
720 * that the peer could add 'amount' of data to its stream.
722 * @param ph performance handle
723 * @param peer identifies the peer
724 * @param amount reserve N bytes for receiving, negative
725 * amounts can be used to undo a (recent) reservation;
726 * @param rcb function to call with the resulting reservation information
727 * @param rcb_cls closure for info
728 * @return NULL on error
729 * @deprecated will be replaced soon
731 struct GNUNET_ATS_ReservationContext *
732 GNUNET_ATS_reserve_bandwidth (struct GNUNET_ATS_PerformanceHandle *ph,
733 const struct GNUNET_PeerIdentity *peer,
735 GNUNET_ATS_ReservationCallback rcb, void *rcb_cls)
737 struct GNUNET_ATS_ReservationContext *rc;
738 struct PendingMessage *p;
739 struct ReservationRequestMessage *m;
741 rc = GNUNET_new (struct GNUNET_ATS_ReservationContext);
745 rc->rcb_cls = rcb_cls;
746 if ((rcb != NULL )&& (amount > 0))rc->undo = GNUNET_YES;
747 GNUNET_CONTAINER_DLL_insert_tail(ph->reservation_head, ph->reservation_tail,
750 p = GNUNET_malloc (sizeof (struct PendingMessage) +
751 sizeof (struct ReservationRequestMessage));
752 p->size = sizeof(struct ReservationRequestMessage);
753 p->is_init = GNUNET_NO;
754 m = (struct ReservationRequestMessage *) &p[1];
755 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST);
756 m->header.size = htons (sizeof(struct ReservationRequestMessage));
757 m->amount = htonl (amount);
759 GNUNET_CONTAINER_DLL_insert_tail(ph->pending_head, ph->pending_tail, p);
766 * Cancel request for reserving bandwidth.
768 * @param rc context returned by the original GNUNET_ATS_reserve_bandwidth call
771 GNUNET_ATS_reserve_bandwidth_cancel (struct GNUNET_ATS_ReservationContext *rc)
778 * Get information about addresses known to the ATS subsystem.
780 * @param handle the performance handle to use
781 * @param peer peer idm can be NULL for all peers
782 * @param all #GNUNET_YES to get information about all addresses or #GNUNET_NO to
783 * get only address currently used
784 * @param infocb callback to call with the addresses,
785 * will callback with address == NULL when done
786 * @param infocb_cls closure for infocb
787 * @return ats performance context
789 struct GNUNET_ATS_AddressListHandle*
790 GNUNET_ATS_performance_list_addresses (struct GNUNET_ATS_PerformanceHandle *handle,
791 const struct GNUNET_PeerIdentity *peer,
793 GNUNET_ATS_AddressInformationCallback infocb,
796 struct GNUNET_ATS_AddressListHandle *alh;
797 struct PendingMessage *p;
798 struct AddressListRequestMessage *m;
800 GNUNET_assert(NULL != handle);
804 alh = GNUNET_new (struct GNUNET_ATS_AddressListHandle);
805 alh->id = handle->id;
808 alh->cb_cls = infocb_cls;
810 alh->all_addresses = all;
812 alh->all_peers = GNUNET_YES;
815 alh->all_peers = GNUNET_NO;
819 GNUNET_CONTAINER_DLL_insert(handle->addresslist_head,
820 handle->addresslist_tail, alh);
822 p = GNUNET_malloc (sizeof (struct PendingMessage) +
823 sizeof (struct AddressListRequestMessage));
824 p->size = sizeof(struct AddressListRequestMessage);
825 m = (struct AddressListRequestMessage *) &p[1];
826 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_REQUEST);
827 m->header.size = htons (sizeof(struct AddressListRequestMessage));
828 m->all = htonl (all);
829 m->id = htonl (alh->id);
834 memset (&m->peer, '\0', sizeof(struct GNUNET_PeerIdentity));
836 GNUNET_CONTAINER_DLL_insert_tail(handle->pending_head,
837 handle->pending_tail,
840 do_transmit (handle);
847 * Cancel a pending address listing operation
849 * @param handle the GNUNET_ATS_AddressListHandle handle to cancel
852 GNUNET_ATS_performance_list_addresses_cancel (struct GNUNET_ATS_AddressListHandle *handle)
854 GNUNET_assert (NULL != handle);
855 GNUNET_CONTAINER_DLL_remove (handle->ph->addresslist_head,
856 handle->ph->addresslist_tail,
858 GNUNET_free (handle);
863 * Convert a GNUNET_ATS_PreferenceType to a string
865 * @param type the preference type
866 * @return a string or NULL if invalid
869 GNUNET_ATS_print_preference_type (uint32_t type)
871 char *prefs[GNUNET_ATS_PreferenceCount] = GNUNET_ATS_PreferenceTypeString;
872 if (type < GNUNET_ATS_PreferenceCount)
879 * Change preferences for the given peer. Preference changes are forgotten if peers
882 * @param ph performance handle
883 * @param peer identifies the peer
884 * @param ... 0-terminated specification of the desired changes
887 GNUNET_ATS_performance_change_preference (struct GNUNET_ATS_PerformanceHandle *ph,
888 const struct GNUNET_PeerIdentity *peer, ...)
890 struct PendingMessage *p;
891 struct ChangePreferenceMessage *m;
894 struct PreferenceInformation *pi;
896 enum GNUNET_ATS_PreferenceKind kind;
900 while (GNUNET_ATS_PREFERENCE_END != (kind =
901 va_arg (ap, enum GNUNET_ATS_PreferenceKind) ))
905 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
907 (void) va_arg (ap, double);
910 case GNUNET_ATS_PREFERENCE_LATENCY:
912 (void) va_arg (ap, double);
920 msize = count * sizeof(struct PreferenceInformation)
921 + sizeof(struct ChangePreferenceMessage);
922 p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
924 p->is_init = GNUNET_NO;
925 m = (struct ChangePreferenceMessage *) &p[1];
926 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE);
927 m->header.size = htons (msize);
928 m->num_preferences = htonl (count);
930 pi = (struct PreferenceInformation *) &m[1];
933 while (GNUNET_ATS_PREFERENCE_END != (kind =
934 va_arg (ap, enum GNUNET_ATS_PreferenceKind) ))
936 pi[count].preference_kind = htonl (kind);
939 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
940 pi[count].preference_value = (float) va_arg (ap, double);
944 case GNUNET_ATS_PREFERENCE_LATENCY:
945 pi[count].preference_value = (float) va_arg (ap, double);
954 GNUNET_CONTAINER_DLL_insert_tail(ph->pending_head, ph->pending_tail, p);
960 * Send feedback to ATS on how good a the requirements for a peer and a
961 * preference is satisfied by ATS
963 * @param ph performance handle
964 * @param scope the time interval this valid for: [now - scope .. now]
965 * @param peer identifies the peer
966 * @param ... 0-terminated specification of the desired changes
969 GNUNET_ATS_performance_give_feedback (struct GNUNET_ATS_PerformanceHandle *ph,
970 const struct GNUNET_PeerIdentity *peer,
971 const struct GNUNET_TIME_Relative scope, ...)
973 struct PendingMessage *p;
974 struct FeedbackPreferenceMessage *m;
977 struct PreferenceInformation *pi;
979 enum GNUNET_ATS_PreferenceKind kind;
983 while (GNUNET_ATS_PREFERENCE_END != (kind =
984 va_arg (ap, enum GNUNET_ATS_PreferenceKind) ))
988 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
990 (void) va_arg (ap, double);
993 case GNUNET_ATS_PREFERENCE_LATENCY:
995 (void) va_arg (ap, double);
1003 msize = count * sizeof(struct PreferenceInformation)
1004 + sizeof(struct FeedbackPreferenceMessage);
1005 p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
1007 p->is_init = GNUNET_NO;
1008 m = (struct FeedbackPreferenceMessage *) &p[1];
1009 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_FEEDBACK);
1010 m->header.size = htons (msize);
1011 m->scope = GNUNET_TIME_relative_hton (scope);
1012 m->num_feedback = htonl (count);
1014 pi = (struct PreferenceInformation *) &m[1];
1016 va_start(ap, scope);
1017 while (GNUNET_ATS_PREFERENCE_END != (kind =
1018 va_arg (ap, enum GNUNET_ATS_PreferenceKind) ))
1020 pi[count].preference_kind = htonl (kind);
1023 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
1024 pi[count].preference_value = (float) va_arg (ap, double);
1028 case GNUNET_ATS_PREFERENCE_LATENCY:
1029 pi[count].preference_value = (float) va_arg (ap, double);
1038 GNUNET_CONTAINER_DLL_insert_tail(ph->pending_head, ph->pending_tail, p);
1042 /* end of ats_api_performance.c */