2 This file is part of GNUnet.
3 Copyright (C) 2011-2015, 2018 GNUnet e.V.
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.
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.
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/>.
19 * @file ats/plugin_ats2_simple.c
20 * @brief ATS simple solver
21 * @author Matthias Wachs
22 * @author Christian Grothoff
28 #include "gnunet_ats_plugin_new.h"
29 #include "gnunet_hello_lib.h"
30 #include "gnunet_peerstore_service.h"
32 #define LOG(kind,...) GNUNET_log_from (kind, "ats-simple",__VA_ARGS__)
36 * Base frequency at which we suggest addresses to transport.
37 * Multiplied by the square of the number of active connections
38 * (and randomized) to calculate the actual frequency at which
39 * we will suggest addresses to the transport. Furthermore, each
40 * address is also bounded by an exponential back-off.
42 #define SUGGEST_FREQ GNUNET_TIME_UNIT_SECONDS
45 * What is the minimum bandwidth we always try to allocate for
46 * any session that is up? (May still be scaled down lower if
47 * the number of sessions is so high that the total bandwidth
48 * is insufficient to allow for this value to be granted.)
50 #define MIN_BANDWIDTH_PER_SESSION 1024
54 * A handle for the proportional solver
60 * Information about preferences and sessions we track
67 * Entry in list of addresses we could try per peer.
83 * Peer this hello belongs to.
88 * The address we could try.
93 * Is a session with this address already up?
94 * If not, set to NULL.
96 struct GNUNET_ATS_SessionHandle *sh;
99 * When does the HELLO expire?
101 struct GNUNET_TIME_Absolute expiration;
104 * When did we try it last?
106 struct GNUNET_TIME_Absolute last_attempt;
109 * Current exponential backoff value.
111 struct GNUNET_TIME_Relative backoff;
114 * Type of the network for this HELLO.
116 enum GNUNET_NetworkType nt;
122 * Internal representation of a session by the plugin.
123 * (If desired, plugin may just use NULL.)
125 struct GNUNET_ATS_SessionHandle
129 * Kept in DLL per peer.
131 struct GNUNET_ATS_SessionHandle *next;
134 * Kept in DLL per peer.
136 struct GNUNET_ATS_SessionHandle *prev;
139 * The session in the main ATS service.
141 struct GNUNET_ATS_Session *session;
144 * Current performance data for this @e session
146 const struct GNUNET_ATS_SessionData *data;
149 * Hello matching this session, or NULL for none.
154 * Peer this session is for.
159 * Address used by this session (largely for debugging).
164 * When did we last update transport about the allocation?
165 * Used to dampen the frequency of updates.
167 struct GNUNET_TIME_Absolute last_allocation;
170 * Last BW-in allocation given to the transport service.
172 struct GNUNET_BANDWIDTH_Value32NBO bw_in;
175 * Last BW-out allocation given to the transport service.
177 struct GNUNET_BANDWIDTH_Value32NBO bw_out;
180 * New BW-in allocation given to the transport service.
185 * New BW-out allocation given to the transport service.
193 * Information about preferences and sessions we track
200 * Kept in DLL per peer.
202 struct GNUNET_ATS_SessionHandle *sh_head;
205 * Kept in DLL per peer.
207 struct GNUNET_ATS_SessionHandle *sh_tail;
212 struct Hello *h_head;
217 struct Hello *h_tail;
220 * The handle for the proportional solver
222 struct SimpleHandle *h;
225 * Watch context where we are currently looking for HELLOs for
228 struct GNUNET_PEERSTORE_WatchContext *wc;
231 * Task used to try again to suggest an address for this peer.
233 struct GNUNET_SCHEDULER_Task *task;
236 * Which peer is this for?
238 struct GNUNET_PeerIdentity pid;
241 * When did we last suggest an address to connect to for this peer?
243 struct GNUNET_TIME_Absolute last_suggestion;
246 * Array where we sum up the bandwidth requests received indexed
247 * by preference kind (see `enum GNUNET_MQ_PreferenceKind`)
249 uint64_t bw_by_pk[GNUNET_MQ_PREFERENCE_COUNT];
255 * Representation of a network (to be expanded...)
261 * Total inbound quota
263 unsigned long long total_quota_in;
266 * Total outbound quota
268 unsigned long long total_quota_out;
273 enum GNUNET_NetworkType type;
279 * A handle for the proportional solver
285 * Our execution environment.
287 struct GNUNET_ATS_PluginEnvironment *env;
290 * Information we track for each peer.
292 struct GNUNET_CONTAINER_MultiPeerMap *peers;
295 * Handle to the peerstore service.
297 struct GNUNET_PEERSTORE_Handle *ps;
300 * Array where we sum up the bandwidth requests received indexed
301 * by preference kind (see `enum GNUNET_MQ_PreferenceKind`) (sums
304 uint64_t bw_by_pk[GNUNET_MQ_PREFERENCE_COUNT];
307 * Information we track per network type (quotas).
309 struct Network networks[GNUNET_NT_COUNT];
315 * Lookup peer in the peers map.
317 * @param h handle to look up in
318 * @param pid peer identity to look up by
319 * @return NULL for not found
322 lookup_peer (struct SimpleHandle *h,
323 const struct GNUNET_PeerIdentity *pid)
325 return GNUNET_CONTAINER_multipeermap_get (h->peers,
331 * Check if there is _any_ interesting information left we
332 * store about the peer in @a p.
334 * @param p peer to test if we can drop the data structure
335 * @return #GNUNET_YES if no information is left in @a p
338 peer_test_dead (struct Peer *p)
340 for (enum GNUNET_MQ_PreferenceKind pk = 0;
341 pk < GNUNET_MQ_PREFERENCE_COUNT;
343 if (0 != p->bw_by_pk[pk])
345 if (NULL != p->sh_head)
352 * Contact the transport service and suggest to it to
353 * try connecting to the address of @a hello. Updates
354 * backoff and timestamp values in the @a hello.
356 * @param hello[in,out] address suggestion to make
359 suggest_hello (struct Hello *hello)
361 struct Peer *p = hello->peer;
362 struct SimpleHandle *h = p->h;
365 = hello->last_attempt
366 = GNUNET_TIME_absolute_get ();
367 hello->backoff = GNUNET_TIME_randomized_backoff (hello->backoff,
368 GNUNET_TIME_absolute_get_remaining (hello->expiration));
369 h->env->suggest_cb (h->env->cls,
376 * Consider suggesting a HELLO (without a session) to transport.
377 * We look at how many active sessions we have for the peer, and
378 * if there are many, reduce the frequency of trying new addresses.
379 * Also, for each address we consider when we last tried it, and
380 * its exponential backoff if the attempt failed. Note that it
381 * is possible that this function is called when no suggestion
384 * In this case, we only calculate the time until we make the next
387 * @param cls a `struct Peer`
390 suggest_start_cb (void *cls)
392 struct Peer *p = cls;
393 struct GNUNET_TIME_Relative delay = GNUNET_TIME_UNIT_ZERO;
394 struct Hello *hello = NULL;
395 struct GNUNET_TIME_Absolute hpt = GNUNET_TIME_UNIT_FOREVER_ABS;
396 struct GNUNET_TIME_Relative xdelay;
397 struct GNUNET_TIME_Absolute xnext;
398 unsigned int num_sessions = 0;
401 /* count number of active sessions */
402 for (struct GNUNET_ATS_SessionHandle *sh = p->sh_head;
406 /* calculate square of number of sessions */
407 num_sessions++; /* start with 1, even if we have zero sessions */
408 if (num_sessions < UINT16_MAX)
409 sq = num_sessions * (uint32_t) num_sessions;
412 xdelay = GNUNET_TIME_randomized_backoff (GNUNET_TIME_relative_multiply (SUGGEST_FREQ,
414 GNUNET_TIME_UNIT_FOREVER_REL);
415 xnext = GNUNET_TIME_relative_to_absolute (xdelay);
418 while (0 == delay.rel_value_us)
421 struct GNUNET_TIME_Absolute xmax;
425 /* We went through the loop already once and found
426 a HELLO that is due *now*, so make a suggestion! */
427 GNUNET_break (NULL == hello->sh);
428 suggest_hello (hello);
430 hpt = GNUNET_TIME_UNIT_FOREVER_ABS;
432 for (struct Hello *pos = p->h_head; NULL != pos; pos = next)
434 struct GNUNET_TIME_Absolute pt;
439 if (0 == GNUNET_TIME_absolute_get_remaining (pos->expiration).rel_value_us)
441 /* expired, remove! */
442 GNUNET_CONTAINER_DLL_remove (p->h_head,
448 pt = GNUNET_TIME_absolute_add (pos->last_attempt,
450 if ( (NULL == hello) ||
451 (pt.abs_value_us < hpt.abs_value_us) )
458 return; /* no HELLOs that could still be tried */
460 /* hpt is now the *earliest* possible time for any HELLO
461 but we might not want to go for as early as possible for
462 this peer. So the actual time is the max of the earliest
463 HELLO and the 'xnext' */
464 xmax = GNUNET_TIME_absolute_max (hpt,
466 delay = GNUNET_TIME_absolute_get_remaining (xmax);
468 p->task = GNUNET_SCHEDULER_add_delayed (delay,
475 * Function called by PEERSTORE for each matching record.
477 * @param cls closure with a `struct Peer`
478 * @param record peerstore record information
479 * @param emsg error message, or NULL if no errors
483 const struct GNUNET_PEERSTORE_Record *record,
486 struct Peer *p = cls;
489 enum GNUNET_NetworkType nt;
490 struct GNUNET_TIME_Absolute expiration;
493 if (0 != memcmp (&p->pid,
495 sizeof (struct GNUNET_PeerIdentity)))
500 if (0 != strcmp (record->key,
501 GNUNET_HELLO_PEERSTORE_KEY))
506 addr = GNUNET_HELLO_extract_address (record->value,
512 return; /* invalid hello, bad signature, other problem */
513 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
515 /* expired, ignore */
519 /* check if addr is already known */
520 for (struct Hello *he = p->h_head;
524 if (0 != strcmp (he->address,
527 if (he->expiration.abs_value_us < expiration.abs_value_us)
529 he->expiration = expiration;
535 /* create new HELLO */
536 alen = strlen (addr) + 1;
537 hello = GNUNET_malloc (sizeof (struct Hello) + alen);
538 hello->address = (const char *) &hello[1];
539 hello->expiration = expiration;
546 GNUNET_CONTAINER_DLL_insert (p->h_head,
549 /* check if sh for this HELLO already exists */
550 for (struct GNUNET_ATS_SessionHandle *sh = p->sh_head;
554 if ( (NULL == sh->address) ||
555 (0 != strcmp (sh->address,
558 GNUNET_assert (NULL == sh->hello);
564 p->task = GNUNET_SCHEDULER_add_now (&suggest_start_cb,
570 * Find or add peer if necessary.
572 * @param h our plugin handle
573 * @param pid the peer identity to add/look for
574 * @return a peer handle
577 peer_add (struct SimpleHandle *h,
578 const struct GNUNET_PeerIdentity *pid)
580 struct Peer *p = lookup_peer (h,
585 p = GNUNET_new (struct Peer);
588 p->wc = GNUNET_PEERSTORE_watch (h->ps,
591 GNUNET_HELLO_PEERSTORE_KEY,
594 GNUNET_assert (GNUNET_YES ==
595 GNUNET_CONTAINER_multipeermap_put (h->peers,
598 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
605 * Free the entry (and associated tasks) of peer @a p.
606 * Note that @a p must be dead already (see #peer_test_dead()).
608 * @param p the peer to free
611 peer_free (struct Peer *p)
613 struct SimpleHandle *h = p->h;
616 GNUNET_assert (NULL == p->sh_head);
617 while (NULL != (hello = p->h_head))
619 GNUNET_CONTAINER_DLL_remove (p->h_head,
622 GNUNET_assert (NULL == hello->sh);
627 GNUNET_SCHEDULER_cancel (p->task);
632 GNUNET_PEERSTORE_watch_cancel (p->wc);
635 GNUNET_assert (GNUNET_YES ==
636 GNUNET_CONTAINER_multipeermap_remove (h->peers,
644 * Check if the new allocation for @a sh is significantly different
645 * from the last one, and if so, tell transport.
647 * @param sh session handle to consider updating transport for
650 consider_notify_transport (struct GNUNET_ATS_SessionHandle *sh)
652 struct Peer *peer = sh->peer;
653 struct SimpleHandle *h = peer->h;
654 enum GNUNET_NetworkType nt = sh->data->prop.nt;
655 struct GNUNET_TIME_Relative delay;
661 delay = GNUNET_TIME_absolute_get_duration (sh->last_allocation);
662 /* A significant change is more than 10% of the quota,
663 which is given in bytes/second */
665 = h->networks[nt].total_quota_in * (delay.rel_value_us / 1000LL) / 1000LL / 10;
667 = h->networks[nt].total_quota_out * (delay.rel_value_us / 1000LL) / 1000LL / 10;
668 delta_in = ( (int64_t) ntohl (sh->bw_in.value__)) - ((int64_t) sh->target_in);
669 delta_out = ( (int64_t) ntohl (sh->bw_in.value__)) - ((int64_t) sh->target_in);
670 /* we want the absolute values */
672 delta_in = - delta_in;
673 if (INT64_MIN == delta_in)
674 delta_in = INT64_MAX; /* Handle corner case: INT_MIN == - INT_MIN */
676 delta_out = - delta_out;
677 if (INT64_MIN == delta_out)
678 delta_out = INT64_MAX; /* Handle corner case: INT_MIN == - INT_MIN */
679 if ( (sig_in > delta_in) &&
680 (sig_out > delta_out) )
681 return; /* insignificant change */
682 /* change is significant, tell transport! */
683 if (sh->target_in > UINT32_MAX)
684 sh->target_in = UINT32_MAX;
685 sh->bw_in.value__ = htonl ((uint32_t) sh->target_in);
686 if (sh->target_out > UINT32_MAX)
687 sh->target_out = UINT32_MAX;
688 sh->bw_out.value__ = htonl ((uint32_t) sh->target_out);
689 sh->last_allocation = GNUNET_TIME_absolute_get ();
690 h->env->allocate_cb (h->env->cls,
699 * Closure for #update_counters and #update_allocation.
706 struct SimpleHandle *h;
709 * Bandwidth that applications would prefer to allocate in this
710 * network type. We initially add all requested allocations to the
711 * respective network type where the given preference is best
712 * satisfied. Later we may rebalance.
714 uint64_t bw_out_by_nt[GNUNET_NT_COUNT];
717 * Current bandwidth utilization for this network type. We simply
718 * add the current goodput up (with some fairness considerations).
720 uint64_t bw_in_by_nt[GNUNET_NT_COUNT];
723 * By how much do we have to scale (up or down) our expectations
724 * for outbound bandwidth?
726 double scale_out[GNUNET_NT_COUNT];
729 * By how much do we have to scale (up or down) our expectations
730 * for inbound bandwidth?
732 double scale_in[GNUNET_NT_COUNT];
738 * Function used to iterate over all peers and collect
741 * @param cls a `struct Counters *`
742 * @param pid identity of the peer we process, unused
743 * @param value a `struct Peer *`
744 * @return #GNUNET_YES (continue to iterate)
747 update_counters (void *cls,
748 const struct GNUNET_PeerIdentity *pid,
751 struct Counters *c = cls;
752 struct Peer *peer = value;
753 struct GNUNET_ATS_SessionHandle *best[GNUNET_MQ_PREFERENCE_COUNT];
759 for (struct GNUNET_ATS_SessionHandle *sh = peer->sh_head;
763 enum GNUNET_NetworkType nt = sh->data->prop.nt;
765 sh->target_out = MIN_BANDWIDTH_PER_SESSION;
766 c->bw_out_by_nt[nt] += MIN_BANDWIDTH_PER_SESSION;
767 c->bw_in_by_nt[nt] += GNUNET_MAX (MIN_BANDWIDTH_PER_SESSION,
768 sh->data->prop.goodput_in);
769 for (enum GNUNET_MQ_PreferenceKind pk = 0;
770 pk < GNUNET_MQ_PREFERENCE_COUNT;
773 /* General rule: always prefer smaller distance if possible,
774 otherwise decide by pk: */
776 case GNUNET_MQ_PREFERENCE_NONE:
778 case GNUNET_MQ_PREFERENCE_BANDWIDTH:
779 /* For bandwidth, we compare the sum of transmitted bytes and
780 confirmed transmitted bytes, so confirmed data counts twice */
781 if ( (NULL == best[pk]) ||
782 (sh->data->prop.distance < best[pk]->data->prop.distance) ||
783 (sh->data->prop.utilization_out + sh->data->prop.goodput_out >
784 best[pk]->data->prop.utilization_out + best[pk]->data->prop.goodput_out) )
786 /* If both are equal (i.e. usually this happens if there is a zero), use
787 latency as a yardstick */
788 if ( (sh->data->prop.utilization_out + sh->data->prop.goodput_out ==
789 best[pk]->data->prop.utilization_out + best[pk]->data->prop.goodput_out) &&
790 (sh->data->prop.distance == best[pk]->data->prop.distance) &&
791 (sh->data->prop.delay.rel_value_us <
792 best[pk]->data->prop.delay.rel_value_us) )
795 case GNUNET_MQ_PREFERENCE_LATENCY:
796 if ( (NULL == best[pk]) ||
797 (sh->data->prop.distance < best[pk]->data->prop.distance) ||
798 ( (sh->data->prop.distance == best[pk]->data->prop.distance) &&
799 (sh->data->prop.delay.rel_value_us <
800 best[pk]->data->prop.delay.rel_value_us) ) )
803 case GNUNET_MQ_PREFERENCE_RELIABILITY:
804 /* For reliability, we consider the ratio of goodput to utilization
805 (but use multiplicative formultations to avoid division by zero) */
806 if ( (NULL == best[pk]) ||
807 (1ULL * sh->data->prop.goodput_out * best[pk]->data->prop.utilization_out >
808 1ULL * sh->data->prop.utilization_out * best[pk]->data->prop.goodput_out) )
810 /* If both are equal (i.e. usually this happens if there is a zero), use
811 latency as a yardstick */
812 if ( (1ULL * sh->data->prop.goodput_out * best[pk]->data->prop.utilization_out ==
813 1ULL * sh->data->prop.utilization_out * best[pk]->data->prop.goodput_out) &&
814 (sh->data->prop.distance == best[pk]->data->prop.distance) &&
815 (sh->data->prop.delay.rel_value_us <
816 best[pk]->data->prop.delay.rel_value_us) )
822 /* for first round, assign target bandwidth simply to sum of
823 requested bandwidth */
824 for (enum GNUNET_MQ_PreferenceKind pk = 0;
825 pk < GNUNET_MQ_PREFERENCE_COUNT;
828 enum GNUNET_NetworkType nt = best[pk]->data->prop.nt;
830 best[pk]->target_out = GNUNET_MIN (peer->bw_by_pk[pk],
831 MIN_BANDWIDTH_PER_SESSION);
832 c->bw_out_by_nt[nt] += (uint64_t) (best[pk]->target_out - MIN_BANDWIDTH_PER_SESSION);
839 * Function used to iterate over all peers and collect
842 * @param cls a `struct Counters *`
843 * @param pid identity of the peer we process, unused
844 * @param value a `struct Peer *`
845 * @return #GNUNET_YES (continue to iterate)
848 update_allocation (void *cls,
849 const struct GNUNET_PeerIdentity *pid,
852 struct Counters *c = cls;
853 struct Peer *peer = value;
856 for (struct GNUNET_ATS_SessionHandle *sh = peer->sh_head;
860 enum GNUNET_NetworkType nt = sh->data->prop.nt;
862 sh->target_out = (uint64_t) (c->scale_out[nt] * sh->target_out);
863 sh->target_in = (uint64_t) (c->scale_in[nt] * sh->target_in);
864 consider_notify_transport (sh);
871 * The world changed, recalculate our allocations.
874 update (struct SimpleHandle *h)
876 struct Counters cnt = {
880 GNUNET_CONTAINER_multipeermap_iterate (h->peers,
883 /* calculate how badly the missmatch between requested
884 allocations and available bandwidth is per network type */
885 for (enum GNUNET_NetworkType nt = 0;
886 nt < GNUNET_NT_COUNT;
889 cnt.scale_out[nt] = 1.0 * cnt.bw_out_by_nt[nt] / h->networks[nt].total_quota_out;
890 cnt.scale_in[nt] = 1.0 * cnt.bw_in_by_nt[nt] / h->networks[nt].total_quota_in;
892 /* recalculate allocations, considering scaling factor, and
893 update transport if the change is significant */
894 GNUNET_CONTAINER_multipeermap_iterate (h->peers,
901 * The plugin should begin to respect a new preference.
903 * @param cls the closure
904 * @param pref the preference to add
905 * @return plugin's internal representation, or NULL
907 static struct GNUNET_ATS_PreferenceHandle *
908 simple_preference_add (void *cls,
909 const struct GNUNET_ATS_Preference *pref)
911 struct SimpleHandle *h = cls;
912 struct Peer *p = peer_add (h,
915 GNUNET_assert (pref->pk < GNUNET_MQ_PREFERENCE_COUNT);
916 p->bw_by_pk[pref->pk] += ntohl (pref->bw.value__);
917 h->bw_by_pk[pref->pk] += ntohl (pref->bw.value__);
924 * The plugin should end respecting a preference.
926 * @param cls the closure
927 * @param ph whatever @e preference_add returned
928 * @param pref the preference to delete
929 * @return plugin's internal representation, or NULL
932 simple_preference_del (void *cls,
933 struct GNUNET_ATS_PreferenceHandle *ph,
934 const struct GNUNET_ATS_Preference *pref)
936 struct SimpleHandle *h = cls;
937 struct Peer *p = lookup_peer (h,
940 GNUNET_assert (NULL != p);
941 GNUNET_assert (pref->pk < GNUNET_MQ_PREFERENCE_COUNT);
942 p->bw_by_pk[pref->pk] -= ntohl (pref->bw.value__);
943 h->bw_by_pk[pref->pk] -= ntohl (pref->bw.value__);
944 if ( (0 == p->bw_by_pk[pref->pk]) &&
945 (GNUNET_YES == peer_test_dead (p)) )
952 * Transport established a new session with performance
953 * characteristics given in @a data.
956 * @param data performance characteristics of @a sh
957 * @param address address information (for debugging)
958 * @return handle by which the plugin will identify this session
960 static struct GNUNET_ATS_SessionHandle *
961 simple_session_add (void *cls,
962 const struct GNUNET_ATS_SessionData *data,
965 struct SimpleHandle *h = cls;
966 struct Peer *p = peer_add (h,
970 struct GNUNET_ATS_SessionHandle *sh;
972 /* setup session handle */
976 alen = strlen (address) + 1;
977 sh = GNUNET_malloc (sizeof (struct GNUNET_ATS_SessionHandle) + alen);
979 sh->session = data->session;
990 sh->address = (const char *) &sh[1];
992 GNUNET_CONTAINER_DLL_insert (p->sh_head,
997 while ( (NULL != hello) &&
998 (0 != strcmp (address,
1000 hello = hello->next;
1004 hello->backoff = GNUNET_TIME_UNIT_ZERO;
1013 * @a data changed for a given @a sh, solver should consider
1014 * the updated performance characteristics.
1016 * @param cls closure
1017 * @param sh session this is about
1018 * @param data performance characteristics of @a sh
1021 simple_session_update (void *cls,
1022 struct GNUNET_ATS_SessionHandle *sh,
1023 const struct GNUNET_ATS_SessionData *data)
1025 struct SimpleHandle *h = cls;
1027 sh->data = data; /* this statement should not really do anything... */
1033 * A session went away. Solver should update accordingly.
1035 * @param cls closure
1036 * @param sh session this is about
1037 * @param data (last) performance characteristics of @a sh
1040 simple_session_del (void *cls,
1041 struct GNUNET_ATS_SessionHandle *sh,
1042 const struct GNUNET_ATS_SessionData *data)
1044 struct SimpleHandle *h = cls;
1045 struct Peer *p = sh->peer;
1046 struct Hello *hello = sh->hello;
1049 GNUNET_CONTAINER_DLL_remove (p->sh_head,
1054 GNUNET_assert (sh == hello->sh);
1056 /* session went down, if necessary restart suggesting
1058 if (NULL == p->task)
1059 p->task = GNUNET_SCHEDULER_add_now (&suggest_start_cb,
1063 /* del peer if otherwise dead */
1064 if ( (NULL == p->sh_head) &&
1065 (GNUNET_YES == peer_test_dead (p)) )
1071 #include "plugin_ats2_common.c"
1075 * Function invoked when the plugin is loaded.
1077 * @param[in,out] cls the `struct GNUNET_ATS_PluginEnvironment *` to use;
1078 * modified to return the API functions (ugh).
1079 * @return the `struct SimpleHandle` to pass as a closure
1082 libgnunet_plugin_ats2_simple_init (void *cls)
1084 static struct GNUNET_ATS_SolverFunctions sf;
1085 struct GNUNET_ATS_PluginEnvironment *env = cls;
1086 struct SimpleHandle *s;
1088 s = GNUNET_new (struct SimpleHandle);
1090 s->peers = GNUNET_CONTAINER_multipeermap_create (128,
1092 s->ps = GNUNET_PEERSTORE_connect (env->cfg);
1094 sf.preference_add = &simple_preference_add;
1095 sf.preference_del = &simple_preference_del;
1096 sf.session_add = &simple_session_add;
1097 sf.session_update = &simple_session_update;
1098 sf.session_del = &simple_session_del;
1099 for (enum GNUNET_NetworkType nt = 0;
1100 nt < GNUNET_NT_COUNT;
1103 const char *name = GNUNET_NT_to_string (nt);
1110 get_quota (env->cfg,
1113 &s->networks[nt].total_quota_in);
1114 get_quota (env->cfg,
1117 &s->networks[nt].total_quota_out);
1118 s->networks[nt].type = nt;
1125 * Function used to unload the plugin.
1127 * @param cls return value from #libgnunet_plugin_ats_proportional_init()
1130 libgnunet_plugin_ats2_simple_done (void *cls)
1132 struct GNUNET_ATS_SolverFunctions *sf = cls;
1133 struct SimpleHandle *s = sf->cls;
1136 GNUNET_CONTAINER_multipeermap_size (s->peers));
1137 GNUNET_CONTAINER_multipeermap_destroy (s->peers);
1138 GNUNET_PEERSTORE_disconnect (s->ps,
1145 /* end of plugin_ats2_simple.c */