more docu
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses_simplistic.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 Christian Grothoff (and other contributing authors)
4
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.
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      General Public License for more details.
14
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.
19 */
20
21 /**
22  * @file ats/gnunet-service-ats_addresses_simplistic.h
23  * @brief ats simplistic ressource assignment
24  * @author Matthias Wachs
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet-service-ats_addresses.h"
30 #include "gnunet_statistics_service.h"
31
32 #define LOG(kind,...) GNUNET_log_from (kind, "ats-simplistic",__VA_ARGS__)
33
34 /**
35  * ATS addresses : simplistic solver
36  *
37  * This solver ssigns in and outbound bandwidth equally for all addresses in
38  * specific network type (WAN, LAN) based on configured in and outbound quota
39  * for this network.
40  *
41  * The solver is notified by addresses about changes to the addresses and
42  * recalculates the bandwith assigned if required. The solver notifies addresses
43  * by calling the GAS_bandwidth_changed_cb callback.
44  *
45  * - Initialization
46  *
47  *
48  * For each peer only a single is selected and marked as "active" in the address
49  * struct.
50  *
51  * E.g.:
52  *
53  * You have the networks WAN and LAN and quotas
54  * WAN_TOTAL_IN, WAN_TOTAL_OUT
55  * LAN_TOTAL_IN, LAN_TOTAL_OUT
56  *
57  * If you have x addresses in the network segment LAN, the quotas are
58  * QUOTA_PER_ADDRESS = LAN_TOTAL_OUT / x
59  *
60  * Quotas are automatically recalculated and reported back when addresses are
61  * - requested
62  *
63  */
64
65 #define PREF_AGING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
66 #define PREF_AGING_FACTOR 0.95
67
68 #define DEFAULT_PREFERENCE 1.0
69 #define MIN_UPDATE_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
70
71 /**
72  * A handle for the simplistic solver
73  */
74 struct GAS_SIMPLISTIC_Handle
75 {
76   /**
77    * Statistics handle
78    */
79
80   struct GNUNET_STATISTICS_Handle *stats;
81
82   /**
83    * Total number of addresses for solver
84    */
85   unsigned int total_addresses;
86
87   /**
88    * Number of active addresses for solver
89    */
90   unsigned int active_addresses;
91
92   /**
93    * Networks array
94    */
95   struct Network *network_entries;
96
97   /**
98    * Number of networks
99    */
100   unsigned int networks;
101
102   /**
103    * Callback
104    */
105   GAS_bandwidth_changed_cb bw_changed;
106
107   /**
108    * Callback cls
109    */
110   void *bw_changed_cls;
111
112   struct GNUNET_CONTAINER_MultiHashMap *prefs;
113
114   struct PreferenceClient *pc_head;
115   struct PreferenceClient *pc_tail;
116 };
117
118 struct Network
119 {
120   /**
121    * ATS network type
122    */
123   unsigned int type;
124
125   /**
126    * Network description
127    */
128   char *desc;
129
130   /**
131    * Total inbound quota
132    *
133    */
134   unsigned long long total_quota_in;
135
136   /**
137    * Total outbound quota
138    *
139    */
140   unsigned long long total_quota_out;
141
142   /**
143    * Number of active addresses for this network
144    */
145   unsigned int active_addresses;
146
147   /**
148    * Number of total addresses for this network
149    */
150   unsigned int total_addresses;
151
152   /**
153    * String for statistics total addresses
154    */
155   char *stat_total;
156
157   /**
158    * String for statistics active addresses
159    */
160   char *stat_active;
161
162   struct AddressWrapper *head;
163   struct AddressWrapper *tail;
164 };
165
166 struct AddressWrapper
167 {
168   struct AddressWrapper *next;
169   struct AddressWrapper *prev;
170
171   struct ATS_Address *addr;
172 };
173
174
175 struct PreferenceClient
176 {
177   struct PreferenceClient *prev;
178   struct PreferenceClient *next;
179   void *client;
180
181   double f_total[GNUNET_ATS_PreferenceCount];
182
183   struct PreferencePeer *p_head;
184   struct PreferencePeer *p_tail;
185 };
186
187
188 struct PreferencePeer
189 {
190   struct PreferencePeer *next;
191   struct PreferencePeer *prev;
192   struct PreferenceClient *client;
193   struct GAS_SIMPLISTIC_Handle *s;
194   struct GNUNET_PeerIdentity id;
195
196   double f[GNUNET_ATS_PreferenceCount];
197   double f_rel[GNUNET_ATS_PreferenceCount];
198   double f_rel_total;
199
200   GNUNET_SCHEDULER_TaskIdentifier aging_task;
201 };
202
203 /**
204  * Get the prefered address for a specific peer
205  *
206  * @param solver the solver handle
207  * @param addresses the address hashmap containing all addresses
208  * @param peer the identity of the peer
209  */
210 const struct ATS_Address *
211 GAS_simplistic_get_preferred_address (void *solver,
212                                struct GNUNET_CONTAINER_MultiHashMap * addresses,
213                                const struct GNUNET_PeerIdentity *peer);
214
215 /**
216  * Init the simplistic problem solving component
217  *
218  * Quotas:
219  * network[i] contains the network type as type GNUNET_ATS_NetworkType[i]
220  * out_quota[i] contains outbound quota for network type i
221  * in_quota[i] contains inbound quota for network type i
222  *
223  * Example
224  * network = {GNUNET_ATS_NET_UNSPECIFIED, GNUNET_ATS_NET_LOOPBACK, GNUNET_ATS_NET_LAN, GNUNET_ATS_NET_WAN, GNUNET_ATS_NET_WLAN}
225  * network[2]   == GNUNET_ATS_NET_LAN
226  * out_quota[2] == 65353
227  * in_quota[2]  == 65353
228  *
229  * @param cfg configuration handle
230  * @param stats the GNUNET_STATISTICS handle
231  * @param network array of GNUNET_ATS_NetworkType with length dest_length
232  * @param out_quota array of outbound quotas
233  * @param in_quota array of outbound quota
234  * @param dest_length array length for quota arrays
235  * @param bw_changed_cb callback for changed bandwidth amounts
236  * @param bw_changed_cb_cls cls for callback
237  * @return handle for the solver on success, NULL on fail
238  */
239 void *
240 GAS_simplistic_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
241                      const struct GNUNET_STATISTICS_Handle *stats,
242                      int *network,
243                      unsigned long long *out_quota,
244                      unsigned long long *in_quota,
245                      int dest_length,
246                      GAS_bandwidth_changed_cb bw_changed_cb,
247                      void *bw_changed_cb_cls)
248 {
249   int c;
250   struct GAS_SIMPLISTIC_Handle *s = GNUNET_malloc (sizeof (struct GAS_SIMPLISTIC_Handle));
251   struct Network * cur;
252   char * net_str[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkTypeString;
253
254
255   s->stats = (struct GNUNET_STATISTICS_Handle *) stats;
256   s->bw_changed = bw_changed_cb;
257   s->bw_changed_cls = bw_changed_cb_cls;
258   s->networks = dest_length;
259   s->network_entries = GNUNET_malloc (dest_length * sizeof (struct Network));
260   s->active_addresses = 0;
261   s->total_addresses = 0;
262   s->prefs = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
263
264   for (c = 0; c < dest_length; c++)
265   {
266       cur = &s->network_entries[c];
267       cur->total_addresses = 0;
268       cur->active_addresses = 0;
269       cur->type = network[c];
270       cur->total_quota_in = in_quota[c];
271       cur->total_quota_out = out_quota[c];
272       cur->desc = net_str[c];
273       GNUNET_asprintf (&cur->stat_total, "# ATS addresses %s total", cur->desc);
274       GNUNET_asprintf (&cur->stat_active, "# ATS active addresses %s total", cur->desc);
275   }
276   return s;
277 }
278
279 static int
280 free_pref (void *cls,
281            const struct GNUNET_HashCode * key,
282            void *value)
283 {
284   float *v = value;
285   GNUNET_free (v);
286   return GNUNET_OK;
287 }
288
289 /**
290  * Shutdown the simplistic problem solving component
291  *
292  * @param solver the respective handle to shutdown
293  */
294 void
295 GAS_simplistic_done (void *solver)
296 {
297   struct GAS_SIMPLISTIC_Handle *s = solver;
298   struct PreferenceClient *pc;
299   struct PreferenceClient *next_pc;
300   struct PreferencePeer *p;
301   struct PreferencePeer *next_p;
302   struct AddressWrapper *cur;
303   struct AddressWrapper *next;
304   int c;
305   GNUNET_assert (s != NULL);
306
307   for (c = 0; c < s->networks; c++)
308   {
309       if (s->network_entries[c].total_addresses > 0)
310       {
311         LOG (GNUNET_ERROR_TYPE_ERROR,
312                     "Had %u addresses for network `%s' not deleted during shutdown\n",
313                     s->network_entries[c].total_addresses,
314                     s->network_entries[c].desc);
315         GNUNET_break (0);
316       }
317
318       if (s->network_entries[c].active_addresses > 0)
319       {
320         LOG (GNUNET_ERROR_TYPE_ERROR,
321                     "Had %u active addresses for network `%s' not deleted during shutdown\n",
322                     s->network_entries[c].active_addresses,
323                     s->network_entries[c].desc);
324         GNUNET_break (0);
325       }
326
327       next = s->network_entries[c].head;
328       while (NULL != (cur = next))
329       {
330           next = cur->next;
331           GNUNET_CONTAINER_DLL_remove (s->network_entries[c].head,
332                                        s->network_entries[c].tail,
333                                        cur);
334           GNUNET_free (cur);
335       }
336       GNUNET_free (s->network_entries[c].stat_total);
337       GNUNET_free (s->network_entries[c].stat_active);
338   }
339   if (s->total_addresses > 0)
340   {
341     LOG (GNUNET_ERROR_TYPE_ERROR,
342                 "Had %u addresses not deleted during shutdown\n",
343                 s->total_addresses);
344     GNUNET_break (0);
345   }
346   if (s->active_addresses > 0)
347   {
348     LOG (GNUNET_ERROR_TYPE_ERROR,
349                 "Had %u active addresses not deleted during shutdown\n",
350                 s->active_addresses);
351     GNUNET_break (0);
352   }
353   GNUNET_free (s->network_entries);
354
355   next_pc = s->pc_head;
356   while (NULL != (pc = next_pc))
357   {
358       next_pc = pc->next;
359       GNUNET_CONTAINER_DLL_remove (s->pc_head, s->pc_tail, pc);
360       next_p = pc->p_head;
361       while (NULL != (p = next_p))
362       {
363           next_p = p->next;
364           if (GNUNET_SCHEDULER_NO_TASK != p->aging_task)
365           {
366                 GNUNET_SCHEDULER_cancel(p->aging_task);
367                 p->aging_task = GNUNET_SCHEDULER_NO_TASK;
368           }
369           GNUNET_CONTAINER_DLL_remove (pc->p_head, pc->p_tail, p);
370           GNUNET_free (p);
371       }
372       GNUNET_free (pc);
373   }
374
375   GNUNET_CONTAINER_multihashmap_iterate (s->prefs, &free_pref, NULL);
376   GNUNET_CONTAINER_multihashmap_destroy (s->prefs);
377   GNUNET_free (s);
378 }
379
380
381 /**
382  * Test if bandwidth is available in this network
383  *
384  * @param s the solver handle
385  * @param net the network type to update
386  * @return GNUNET_YES or GNUNET_NO
387  */
388
389 static int
390 bw_available_in_network (struct Network *net)
391 {
392   unsigned int na = net->active_addresses + 1;
393   uint32_t min_bw = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
394   if (((net->total_quota_in / na) > min_bw) &&
395       ((net->total_quota_out / na) > min_bw))
396   {    
397     LOG (GNUNET_ERROR_TYPE_DEBUG,
398          "Enough bandwidth available for %u active addresses in network `%s'\n",
399          na,
400          net->desc);
401                                                                       
402     return GNUNET_YES;
403   }
404     LOG (GNUNET_ERROR_TYPE_DEBUG,
405          "Not enough bandwidth available for %u active addresses in network `%s'\n",
406          na,
407          net->desc);  
408   return GNUNET_NO;
409 }
410
411
412 /**
413  * Update the quotas for a network type
414  *
415  * @param s the solver handle
416  * @param net the network type to update
417  * @param address_except address excluded from notifcation, since we suggest
418  * this address
419  */
420 static void
421 update_quota_per_network (struct GAS_SIMPLISTIC_Handle *s,
422                           struct Network *net,
423                           struct ATS_Address *address_except)
424 {
425   unsigned long long remaining_quota_in = 0;
426   unsigned long long quota_out_used = 0;
427
428   unsigned long long remaining_quota_out = 0;
429   unsigned long long quota_in_used = 0;
430   uint32_t min_bw = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
431   double total_prefs; /* Important: has to be double not float due to precision */
432   double cur_pref; /* Important: has to be double not float due to precision */
433   double *t = NULL; /* Important: has to be double not float due to precision */
434
435   unsigned long long assigned_quota_in = 0;
436   unsigned long long assigned_quota_out = 0;
437   struct AddressWrapper *cur;
438
439   LOG (GNUNET_ERROR_TYPE_DEBUG,
440               "Recalculate quota for network type `%s' for %u addresses (in/out): %llu/%llu \n",
441               net->desc, net->active_addresses, net->total_quota_in, net->total_quota_in);
442
443   if (net->active_addresses == 0)
444     return; /* no addresses to update */
445
446   /* Idea TODO
447    *
448    * Assign every peer in network minimum Bandwidth
449    * Distribute bandwidth left according to preference
450    */
451
452   if ((net->active_addresses * min_bw) > net->total_quota_in)
453   {
454     GNUNET_break (0);
455     return;
456   }
457   if ((net->active_addresses * min_bw) > net->total_quota_out)
458   {
459     GNUNET_break (0);
460     return;
461   }
462
463   remaining_quota_in = net->total_quota_in - (net->active_addresses * min_bw);
464   remaining_quota_out = net->total_quota_out - (net->active_addresses * min_bw);
465   LOG (GNUNET_ERROR_TYPE_DEBUG, "Remaining bandwidth : (in/out): %llu/%llu \n",
466               remaining_quota_in, remaining_quota_out);
467   total_prefs = 0.0;
468   for (cur = net->head; NULL != cur; cur = cur->next)
469   {
470       if (GNUNET_YES == cur->addr->active)
471       {
472         t = GNUNET_CONTAINER_multihashmap_get (s->prefs, &cur->addr->peer.hashPubKey);
473         if (NULL == t)
474                 total_prefs += DEFAULT_PREFERENCE;
475         else
476          {
477                         total_prefs += (*t);
478          }
479       }
480   }
481   for (cur = net->head; NULL != cur; cur = cur->next)
482   {
483      if (GNUNET_YES == cur->addr->active)
484      {
485        cur_pref = 0.0;
486        t = GNUNET_CONTAINER_multihashmap_get (s->prefs, &cur->addr->peer.hashPubKey);
487        if (NULL == t)
488          cur_pref = DEFAULT_PREFERENCE;
489        else
490          cur_pref = (*t);
491        assigned_quota_in = min_bw + ((cur_pref / total_prefs) * remaining_quota_in);
492        assigned_quota_out = min_bw + ((cur_pref / total_prefs) * remaining_quota_out);
493
494        LOG (GNUNET_ERROR_TYPE_DEBUG,
495                    "New quota for peer `%s' with preference (cur/total) %.3f/%.3f (in/out): %llu / %llu\n",
496                    GNUNET_i2s (&cur->addr->peer),
497                    cur_pref, total_prefs,
498                    assigned_quota_in, assigned_quota_out);
499      }
500      else
501      {
502        assigned_quota_in = 0;
503        assigned_quota_out = 0;
504      }
505
506      quota_in_used += assigned_quota_in;
507      quota_out_used += assigned_quota_out;
508      /* Prevent overflow due to rounding errors */
509      if (assigned_quota_in > UINT32_MAX)
510        assigned_quota_in = UINT32_MAX;
511      if (assigned_quota_out > UINT32_MAX)
512        assigned_quota_out = UINT32_MAX;
513
514      /* Compare to current bandwidth assigned */
515      if ((assigned_quota_in != ntohl(cur->addr->assigned_bw_in.value__)) ||
516          (assigned_quota_out != ntohl(cur->addr->assigned_bw_out.value__)))
517      {
518        cur->addr->assigned_bw_in.value__ = htonl (assigned_quota_in);
519        cur->addr->assigned_bw_out.value__ = htonl (assigned_quota_out);
520        /* Notify on change */
521        if ((GNUNET_YES == cur->addr->active) && (cur->addr != address_except))
522          s->bw_changed (s->bw_changed_cls, cur->addr);
523      }
524
525   }
526   LOG (GNUNET_ERROR_TYPE_DEBUG,
527                           "Total bandwidth assigned is (in/out): %llu /%llu\n",
528                           quota_in_used,
529                           quota_out_used);
530   if (quota_out_used > net->total_quota_out + 1) /* +1 is required due to rounding errors */
531   {
532       LOG (GNUNET_ERROR_TYPE_ERROR,
533                             "Total outbound bandwidth assigned is larger than allowed (used/allowed) for %u active addresses: %llu / %llu\n",
534                             net->active_addresses,
535                             quota_out_used,
536                             net->total_quota_out);
537   }
538   if (quota_in_used > net->total_quota_in + 1) /* +1 is required due to rounding errors */
539   {
540       LOG (GNUNET_ERROR_TYPE_ERROR,
541                             "Total inbound bandwidth assigned is larger than allowed (used/allowed) for %u active addresses: %llu / %llu\n",
542                             net->active_addresses,
543                             quota_in_used,
544                             net->total_quota_in);
545   }
546 }
547
548 static void
549 update_all_networks (struct GAS_SIMPLISTIC_Handle *s)
550 {
551         int i;
552         for (i = 0; i < s->networks; i++)
553                 update_quota_per_network (s, &s->network_entries[i], NULL);
554
555 }
556
557 static void
558 addresse_increment (struct GAS_SIMPLISTIC_Handle *s,
559                                 struct Network *net,
560                                 int total,
561                                 int active)
562 {
563   if (GNUNET_YES == total)
564   {
565       s->total_addresses ++;
566       net->total_addresses ++;
567       GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", 1, GNUNET_NO);
568       GNUNET_STATISTICS_update (s->stats, net->stat_total, 1, GNUNET_NO);
569   }
570   if (GNUNET_YES == active)
571   {
572     net->active_addresses ++;
573     s->active_addresses ++;
574     GNUNET_STATISTICS_update (s->stats, "# ATS active addresses total", 1, GNUNET_NO);
575     GNUNET_STATISTICS_update (s->stats, net->stat_active, 1, GNUNET_NO);
576   }
577
578 }
579
580 static int
581 addresse_decrement (struct GAS_SIMPLISTIC_Handle *s,
582                     struct Network *net,
583                     int total,
584                     int active)
585 {
586   int res = GNUNET_OK;
587   if (GNUNET_YES == total)
588   {
589     if (s->total_addresses < 1)
590     {
591       GNUNET_break (0);
592       res = GNUNET_SYSERR;
593     }
594     else
595     {
596       s->total_addresses --;
597       GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", -1, GNUNET_NO);
598     }
599     if (net->total_addresses < 1)
600     {
601       GNUNET_break (0);
602       res = GNUNET_SYSERR;
603     }
604     else
605     {
606       net->total_addresses --;
607       GNUNET_STATISTICS_update (s->stats, net->stat_total, -1, GNUNET_NO);
608     }
609   }
610
611   if (GNUNET_YES == active)
612   {
613     if (net->active_addresses < 1)
614     {
615       GNUNET_break (0);
616       res = GNUNET_SYSERR;
617     }
618     else
619     {
620       net->active_addresses --;
621       GNUNET_STATISTICS_update (s->stats, net->stat_active, -1, GNUNET_NO);
622     }
623     if (s->active_addresses < 1)
624     {
625       GNUNET_break (0);
626       res = GNUNET_SYSERR;
627     }
628     else
629     {
630       s->active_addresses --;
631       GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", -1, GNUNET_NO);
632     }
633   }
634   return res;
635 }
636
637
638 /**
639  * Add a single address to the solve
640  *
641  * @param solver the solver Handle
642  * @param addresses the address hashmap containing all addresses
643  * @param address the address to add
644  */
645 void
646 GAS_simplistic_address_add (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
647 {
648   struct GAS_SIMPLISTIC_Handle *s = solver;
649   struct Network *net = NULL;
650   struct AddressWrapper *aw = NULL;
651
652   GNUNET_assert (NULL != s);
653   int c;
654   for (c = 0; c < s->networks; c++)
655   {
656       net = &s->network_entries[c];
657       if (address->atsp_network_type == net->type)
658           break;
659   }
660   if (NULL == net)
661   {
662     GNUNET_break (0);
663     return;
664   }
665
666   aw = GNUNET_malloc (sizeof (struct AddressWrapper));
667   aw->addr = address;
668   GNUNET_CONTAINER_DLL_insert (net->head, net->tail, aw);
669   addresse_increment (s, net, GNUNET_YES, GNUNET_NO);
670   aw->addr->solver_information = net;
671
672
673   LOG (GNUNET_ERROR_TYPE_DEBUG, "After adding address now total %u and active %u addresses in network `%s'\n",
674       net->total_addresses,
675       net->active_addresses,
676       net->desc);
677 }
678
679 /**
680  * Remove an address from the solver
681  *
682  * @param solver the solver handle
683  * @param addresses the address hashmap containing all addresses
684  * @param address the address to remove
685  * @param session_only delete only session not whole address
686  */
687 void
688 GAS_simplistic_address_delete (void *solver,
689     struct GNUNET_CONTAINER_MultiHashMap * addresses,
690     struct ATS_Address *address, int session_only)
691 {
692   struct GAS_SIMPLISTIC_Handle *s = solver;
693   struct Network *net;
694   struct AddressWrapper *aw;
695
696   /* Remove an adress completely, we have to:
697    * - Remove from specific network
698    * - Decrease number of total addresses
699    * - If active:
700    *   - decrease number of active addreses
701    *   - update quotas
702    */
703
704   net = (struct Network *) address->solver_information;
705
706   if (GNUNET_NO == session_only)
707   {
708     LOG (GNUNET_ERROR_TYPE_DEBUG, "Deleting %s address %p for peer `%s' from network `%s' (total: %u/ active: %u)\n",
709         (GNUNET_NO == address->active) ? "inactive" : "active",
710         address, GNUNET_i2s (&address->peer),
711         net->desc, net->total_addresses, net->active_addresses);
712
713     /* Remove address */
714     addresse_decrement (s, net, GNUNET_YES, GNUNET_NO);
715     for (aw = net->head; NULL != aw; aw = aw->next)
716     {
717         if (aw->addr == address)
718           break;
719     }
720     if (NULL == aw )
721     {
722         GNUNET_break (0);
723         return;
724     }
725     GNUNET_CONTAINER_DLL_remove (net->head, net->tail, aw);
726     GNUNET_free (aw);
727   }
728   else
729   {
730       /* Remove session only: remove if active and update */
731       LOG (GNUNET_ERROR_TYPE_DEBUG, "Deleting %s session %p for peer `%s' from network `%s' (total: %u/ active: %u)\n",
732           (GNUNET_NO == address->active) ? "inactive" : "active",
733           address, GNUNET_i2s (&address->peer),
734           net->desc, net->total_addresses, net->active_addresses);
735   }
736
737   if (GNUNET_YES == address->active)
738   {
739       /* Address was active, remove from network and update quotas*/
740       address->active = GNUNET_NO;
741       if (GNUNET_SYSERR == addresse_decrement (s, net, GNUNET_NO, GNUNET_YES))
742         GNUNET_break (0);
743       update_quota_per_network (s, net, NULL);
744   }
745   LOG (GNUNET_ERROR_TYPE_DEBUG, "After deleting address now total %u and active %u addresses in network `%s'\n",
746       net->total_addresses,
747       net->active_addresses,
748       net->desc);
749
750 }
751
752 static struct Network *
753 find_network (struct GAS_SIMPLISTIC_Handle *s, uint32_t type)
754 {
755   int c;
756   for (c = 0 ; c < s->networks; c++)
757   {
758       if (s->network_entries[c].type == type)
759         return &s->network_entries[c];
760   }
761   return NULL;
762 }
763
764 /**
765  * Updates a single address in the solve
766  *
767  * @param solver the solver Handle
768  * @param addresses the address hashmap containing all addresses
769  * @param address the update address
770  * @param session the new session (if changed otherwise current)
771  * @param in_use the new address in use state (if changed otherwise current)
772  * @param atsi the latest ATS information
773  * @param atsi_count the atsi count
774  */
775 void
776 GAS_simplistic_address_update (void *solver,
777                               struct GNUNET_CONTAINER_MultiHashMap *addresses,
778                               struct ATS_Address *address,
779                               uint32_t session,
780                               int in_use,
781                               const struct GNUNET_ATS_Information *atsi,
782                               uint32_t atsi_count)
783 {
784   struct ATS_Address *new;
785   struct GAS_SIMPLISTIC_Handle *s = (struct GAS_SIMPLISTIC_Handle *) solver;
786   int i;
787   uint32_t value;
788   uint32_t type;
789   int save_active = GNUNET_NO;
790   struct Network *new_net = NULL;
791   for (i = 0; i < atsi_count; i++)
792   {
793     type = ntohl (atsi[i].type);
794     value = ntohl (atsi[i].value);
795     switch (type)
796     {
797     case GNUNET_ATS_UTILIZATION_UP:
798       //if (address->atsp_utilization_out.value__ != atsi[i].value)
799
800       break;
801     case GNUNET_ATS_UTILIZATION_DOWN:
802       //if (address->atsp_utilization_in.value__ != atsi[i].value)
803
804       break;
805     case GNUNET_ATS_QUALITY_NET_DELAY:
806       //if (address->atsp_latency.rel_value != value)
807
808       break;
809     case GNUNET_ATS_QUALITY_NET_DISTANCE:
810       //if (address->atsp_distance != value)
811
812       break;
813     case GNUNET_ATS_COST_WAN:
814       //if (address->atsp_cost_wan != value)
815
816       break;
817     case GNUNET_ATS_COST_LAN:
818       //if (address->atsp_cost_lan != value)
819
820       break;
821     case GNUNET_ATS_COST_WLAN:
822       //if (address->atsp_cost_wlan != value)
823
824       break;
825     case GNUNET_ATS_NETWORK_TYPE:
826       if (address->atsp_network_type != value)
827       {
828
829         LOG (GNUNET_ERROR_TYPE_DEBUG, "Network type changed, moving %s address from `%s' to `%s'\n",
830             (GNUNET_YES == address->active) ? "active" : "inactive",
831             GNUNET_ATS_print_network_type(address->atsp_network_type),
832             GNUNET_ATS_print_network_type(value));
833
834         save_active = address->active;
835         /* remove from old network */
836         GAS_simplistic_address_delete (solver, addresses, address, GNUNET_NO);
837
838         /* set new network type */
839         address->atsp_network_type = value;
840         new_net = find_network (solver, value);
841         address->solver_information = new_net;
842         if (address->solver_information == NULL)
843         {
844             GNUNET_break (0);
845             address->atsp_network_type = GNUNET_ATS_NET_UNSPECIFIED;
846             return;
847         }
848
849         /* Add to new network and update*/
850         GAS_simplistic_address_add (solver, addresses, address);
851         if (GNUNET_YES == save_active)
852         {
853           /* check if bandwidth available in new network */
854           if (GNUNET_YES == (bw_available_in_network (new_net)))
855           {
856               /* Suggest updated address */
857               address->active = GNUNET_YES;
858               addresse_increment (s, new_net, GNUNET_NO, GNUNET_YES);
859               update_quota_per_network (solver, new_net, NULL);
860           }
861           else
862           {
863             LOG (GNUNET_ERROR_TYPE_DEBUG, "Not enough bandwidth in new network, suggesting alternative address ..\n");
864
865             /* Set old address to zero bw */
866             address->assigned_bw_in = GNUNET_BANDWIDTH_value_init (0);
867             address->assigned_bw_out = GNUNET_BANDWIDTH_value_init (0);
868             s->bw_changed  (s->bw_changed_cls, address);
869
870             /* Find new address to suggest since no bandwidth in network*/
871             new = (struct ATS_Address *) GAS_simplistic_get_preferred_address (s, addresses, &address->peer);
872             if (NULL != new)
873             {
874                 /* Have an alternative address to suggest */
875                 s->bw_changed  (s->bw_changed_cls, new);
876             }
877
878           }
879         }
880       }
881       break;
882     case GNUNET_ATS_ARRAY_TERMINATOR:
883       break;
884     default:
885       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
886                   "Received unsupported ATS type %u\n", type);
887       GNUNET_break (0);
888       break;
889
890     }
891
892   }
893   if (address->session_id != session)
894   {
895       LOG (GNUNET_ERROR_TYPE_DEBUG,
896                   "Session changed from %u to %u\n", address->session_id, session);
897       address->session_id = session;
898   }
899   if (address->used != in_use)
900   {
901       LOG (GNUNET_ERROR_TYPE_DEBUG,
902                   "Usage changed from %u to %u\n", address->used, in_use);
903       address->used = in_use;
904   }
905
906 }
907
908
909
910 /**
911  * Find a "good" address to use for a peer.  If we already have an existing
912  * address, we stick to it.  Otherwise, we pick by lowest distance and then
913  * by lowest latency.
914  *
915  * @param cls the 'struct ATS_Address**' where we store the result
916  * @param key unused
917  * @param value another 'struct ATS_Address*' to consider using
918  * @return GNUNET_OK (continue to iterate)
919  */
920 static int
921 find_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
922 {
923   struct ATS_Address **previous_p = cls;
924   struct ATS_Address *current = (struct ATS_Address *) value;
925   struct ATS_Address *previous = *previous_p;
926   struct GNUNET_TIME_Absolute now;
927   struct Network *net = (struct Network *) current->solver_information;
928
929   now = GNUNET_TIME_absolute_get();
930
931   if (current->blocked_until.abs_value == GNUNET_TIME_absolute_max (now, current->blocked_until).abs_value)
932   {
933     /* This address is blocked for suggestion */
934     LOG (GNUNET_ERROR_TYPE_DEBUG,
935                 "Address %p blocked for suggestion for %llu ms \n",
936                 current,
937                 GNUNET_TIME_absolute_get_difference(now, current->blocked_until).rel_value);
938     return GNUNET_OK;
939   }
940
941   if (GNUNET_NO == bw_available_in_network (net))
942     return GNUNET_OK; /* There's no bandwidth available in this network */
943
944   if (NULL != previous)
945   {
946     if ((0 == strcmp (previous->plugin, "tcp")) &&
947         (0 == strcmp (current->plugin, "tcp")))
948     {
949       if ((0 != previous->addr_len) &&
950           (0 == current->addr_len))
951       {
952         /* saved address was an outbound address, but we have an inbound address */
953         *previous_p = current;
954         return GNUNET_OK;
955       }
956       if (0 == previous->addr_len)
957       {
958         /* saved address was an inbound address, so do not overwrite */
959         return GNUNET_OK;
960       }
961     }
962   }
963
964   if (NULL == previous)
965   {
966     *previous_p = current;
967     return GNUNET_OK;
968   }
969   if ((ntohl (previous->assigned_bw_in.value__) == 0) &&
970       (ntohl (current->assigned_bw_in.value__) > 0))
971   {
972     /* stick to existing connection */
973     *previous_p = current;
974     return GNUNET_OK;
975   }
976   if (previous->atsp_distance > current->atsp_distance)
977   {
978     /* user shorter distance */
979     *previous_p = current;
980     return GNUNET_OK;
981   }
982   if (previous->atsp_latency.rel_value > current->atsp_latency.rel_value)
983   {
984     /* user lower latency */
985     *previous_p = current;
986     return GNUNET_OK;
987   }
988   /* don't care */
989   return GNUNET_OK;
990 }
991
992 static int
993 find_active_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
994 {
995   struct ATS_Address * dest = (struct ATS_Address *) (*(struct ATS_Address **)cls);
996   struct ATS_Address * aa = (struct ATS_Address *) value;
997
998   if (GNUNET_YES == aa->active)
999   {
1000       if (dest != NULL)
1001       {
1002           /* should never happen */
1003           LOG (GNUNET_ERROR_TYPE_ERROR, "Multiple active addresses for peer `%s'\n", GNUNET_i2s (&aa->peer));
1004           GNUNET_break (0);
1005           return GNUNET_NO;
1006       }
1007       dest = aa;
1008   }
1009   return GNUNET_OK;
1010 }
1011
1012 static struct ATS_Address *
1013 find_active_address (void *solver,
1014                      struct GNUNET_CONTAINER_MultiHashMap * addresses,
1015                      const struct GNUNET_PeerIdentity *peer)
1016 {
1017   struct ATS_Address * dest = NULL;
1018
1019   GNUNET_CONTAINER_multihashmap_get_multiple(addresses,
1020        &peer->hashPubKey,
1021        &find_active_address_it, &dest);
1022   return dest;
1023 }
1024
1025 /**
1026  * Get the prefered address for a specific peer
1027  *
1028  * @param solver the solver handle
1029  * @param addresses the address hashmap containing all addresses
1030  * @param peer the identity of the peer
1031  */
1032 const struct ATS_Address *
1033 GAS_simplistic_get_preferred_address (void *solver,
1034                                struct GNUNET_CONTAINER_MultiHashMap * addresses,
1035                                const struct GNUNET_PeerIdentity *peer)
1036 {
1037   struct GAS_SIMPLISTIC_Handle *s = solver;
1038   struct Network *net_prev;
1039   struct Network *net_cur;
1040   struct ATS_Address *cur;
1041   struct ATS_Address *prev;
1042
1043   GNUNET_assert (s != NULL);
1044   cur = NULL;
1045   /* Get address with: stick to current address, lower distance, lower latency */
1046   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
1047                                               &find_address_it, &cur);
1048   if (NULL == cur)
1049   {
1050     LOG (GNUNET_ERROR_TYPE_DEBUG, "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
1051     return NULL;
1052   }
1053
1054   LOG (GNUNET_ERROR_TYPE_DEBUG, "Suggesting %s address %p for peer `%s'\n",
1055       (GNUNET_NO == cur->active) ? "inactive" : "active",
1056       cur, GNUNET_i2s (peer));
1057   net_cur = (struct Network *) cur->solver_information;
1058   if (GNUNET_YES == cur->active)
1059   {
1060       /* This address was selected previously, so no need to update quotas */
1061       return cur;
1062   }
1063
1064   /* This address was not active, so we have to:
1065    *
1066    * - mark previous active address as not active
1067    * - update quota for previous address network
1068    * - update quota for this address network
1069    */
1070
1071   prev = find_active_address (s, addresses, peer);
1072   if (NULL != prev)
1073   {
1074       net_prev = (struct Network *) prev->solver_information;
1075       prev->active = GNUNET_NO; /* No active any longer */
1076       prev->assigned_bw_in = GNUNET_BANDWIDTH_value_init (0); /* no bw assigned */
1077       prev->assigned_bw_out = GNUNET_BANDWIDTH_value_init (0); /* no bw assigned */
1078       s->bw_changed (s->bw_changed_cls, prev); /* notify about bw change, REQUIRED? */
1079       if (GNUNET_SYSERR == addresse_decrement (s, net_prev, GNUNET_NO, GNUNET_YES))
1080         GNUNET_break (0);
1081       update_quota_per_network (s, net_prev, NULL);
1082   }
1083
1084   if (GNUNET_NO == (bw_available_in_network (cur->solver_information)))
1085   {
1086     GNUNET_break (0); /* This should never happen*/
1087     return NULL;
1088   }
1089
1090   cur->active = GNUNET_YES;
1091   addresse_increment(s, net_cur, GNUNET_NO, GNUNET_YES);
1092   update_quota_per_network (s, net_cur, cur);
1093
1094   return cur;
1095 }
1096
1097 static void
1098 recalculate_preferences (struct PreferencePeer *p)
1099 {
1100         struct GAS_SIMPLISTIC_Handle *s = p->s;
1101         struct PreferencePeer *p_cur;
1102         struct PreferenceClient *c_cur = p->client;
1103         double p_rel_global;
1104   double *dest;
1105   int kind;
1106   int rkind;
1107   int clients;
1108
1109   /**
1110    * Idea:
1111    *
1112    * We have:
1113    * Set of clients c
1114    * Set of peers p_i in P
1115    * Set of preference kinds k
1116    * A preference value f_k_p_i with an unknown range
1117    *
1118    * We get:
1119    * A client specific relative preference f_p_i_rel [1..2] for all peers
1120    *
1121    * For every client c
1122    * {
1123    *   For every preference kind k:
1124    *   {
1125    *     We remember for the preference f_p_i for each peer p_i.
1126    *     We have a default preference value f_p_i = 0
1127    *     We have a sum of all preferences f_t = sum (f_p_i)
1128    *     So we can calculate a relative preference value fr_p_i:
1129    *
1130    *     f_k_p_i_rel = (f_t + f_p_i) / f_t
1131    *     f_k_p_i_rel = [1..2], default 1.0
1132    *    }
1133    *    f_p_i_rel = sum (f_k_p_i_rel) / #k
1134    * }
1135    *
1136    **/
1137
1138   /* For this client: for all preferences, except TERMINATOR */
1139   for (kind = GNUNET_ATS_PREFERENCE_END + 1 ; kind < GNUNET_ATS_PreferenceCount; kind ++)
1140   {
1141           /* Recalcalculate total preference for this quality kind over all peers*/
1142           c_cur->f_total[kind] = 0;
1143           for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
1144                 c_cur->f_total[kind] += p_cur->f[kind];
1145
1146           LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p has total preference for %s of %.3f\n",
1147                         c_cur->client,
1148               GNUNET_ATS_print_preference_type (kind),
1149               c_cur->f_total[kind]);
1150
1151           /* Recalcalculate relative preference for all peers */
1152           for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
1153           {
1154             /* Calculate relative preference for specific kind */
1155                 if (0.0 == c_cur->f_total[kind])
1156                 {
1157                                 /* No one has preference, so set default preference */
1158                                 p_cur->f_rel[kind] = DEFAULT_PREFERENCE;
1159                 }
1160                 else
1161                 {
1162                                 p_cur->f_rel[kind] = (c_cur->f_total[kind] + p_cur->f[kind]) / c_cur->f_total[kind];
1163                 }
1164             LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p: peer `%s' has relative preference for %s of %.3f\n",
1165                         c_cur->client,
1166                 GNUNET_i2s (&p_cur->id),
1167                 GNUNET_ATS_print_preference_type (kind),
1168                 p_cur->f_rel[kind]);
1169
1170             /* Calculate peer relative preference */
1171             /* Start with kind = 1 to exclude terminator */
1172             p_cur->f_rel_total = 0;
1173             for (rkind = GNUNET_ATS_PREFERENCE_END + 1; rkind < GNUNET_ATS_PreferenceCount; rkind ++)
1174             {
1175                 p_cur->f_rel_total += p_cur->f_rel[rkind];
1176             }
1177             p_cur->f_rel_total /=  (GNUNET_ATS_PreferenceCount - 1.0); /* -1 due to terminator */
1178             LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p: peer `%s' has total relative preference of %.3f\n",
1179                         c_cur->client,
1180                 GNUNET_i2s (&p_cur->id),
1181                 p_cur->f_rel_total);
1182           }
1183   }
1184
1185   /* Calculcate global total relative peer preference over all clients */
1186   p_rel_global = 0.0;
1187   clients = 0;
1188   for (c_cur = s->pc_head; NULL != c_cur; c_cur = c_cur->next)
1189   {
1190       for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
1191           if (0 == memcmp (&p_cur->id, &p->id, sizeof (p_cur->id)))
1192               break;
1193       if (NULL != p_cur)
1194       {
1195           clients++;
1196           p_rel_global += p_cur->f_rel_total;
1197       }
1198   }
1199   p_rel_global /= clients;
1200   LOG (GNUNET_ERROR_TYPE_DEBUG, "Global preference value for peer `%s': %.3f\n",
1201       GNUNET_i2s (&p->id), p_rel_global);
1202
1203   /* Update global map */
1204   if (NULL != (dest = GNUNET_CONTAINER_multihashmap_get(s->prefs, &p->id.hashPubKey)))
1205       (*dest) = p_rel_global;
1206   else
1207   {
1208       dest = GNUNET_malloc (sizeof (double));
1209       (*dest) = p_rel_global;
1210       GNUNET_CONTAINER_multihashmap_put(s->prefs,
1211           &p->id.hashPubKey,
1212           dest,
1213           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1214   }
1215 }
1216
1217 static void
1218 update_preference (struct PreferencePeer *p,
1219                                                                          enum GNUNET_ATS_PreferenceKind kind,
1220                                                          float score_f)
1221 {
1222         double score = score_f;
1223
1224   /* Update preference value according to type */
1225   switch (kind) {
1226     case GNUNET_ATS_PREFERENCE_BANDWIDTH:
1227     case GNUNET_ATS_PREFERENCE_LATENCY:
1228       p->f[kind] = (p->f[kind] + score) / 2;
1229       break;
1230     case GNUNET_ATS_PREFERENCE_END:
1231       break;
1232     default:
1233       break;
1234   }
1235   recalculate_preferences(p);
1236   update_all_networks (p->s);
1237 }
1238
1239
1240 static void
1241 preference_aging (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1242 {
1243         int i;
1244         double *t = NULL;
1245         double backup;
1246         struct PreferencePeer *p = cls;
1247         GNUNET_assert (NULL != p);
1248
1249
1250         p->aging_task = GNUNET_SCHEDULER_NO_TASK;
1251
1252   LOG (GNUNET_ERROR_TYPE_DEBUG, "Aging preferences for peer `%s'\n",
1253                 GNUNET_i2s (&p->id));
1254
1255   /* Issue for aging :
1256    *
1257    * Not for every peer preference values are set by default, so reducing the
1258    * absolute preference value does not help for aging because it does not have
1259    * influence on the relative values.
1260    *
1261    * So we have to reduce the relative value to have an immediate impact on
1262    * quota calculation. In addition we cannot call recalculate_preferences here
1263    * but instead reduce the absolute value to have an aging impact on future
1264    * calls to change_preference where recalculate_preferences is called
1265    *
1266    */
1267   /* Aging absolute values: */
1268   for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
1269   {
1270                 if (p->f[i] > 1.0)
1271                 {
1272                         backup = p->f[i];
1273                         p->f[i] *= PREF_AGING_FACTOR;
1274                         LOG (GNUNET_ERROR_TYPE_DEBUG, "Aged preference for peer `%s' from %.3f to %.3f\n",
1275                         GNUNET_i2s (&p->id), backup, p->f[i]);
1276                 }
1277   }
1278   /* Updating relative value */
1279   t = GNUNET_CONTAINER_multihashmap_get (p->s->prefs, &p->id.hashPubKey);
1280   if (NULL == t)
1281   {
1282         GNUNET_break (0);
1283   }
1284   else
1285   {
1286                 if ((*t) > 1.0)
1287                         (*t) = (*t) * PREF_AGING_FACTOR;
1288                 else
1289                         (*t) = 1.0;
1290                 update_all_networks (p->s);
1291   }
1292   p->aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL,
1293                 &preference_aging, p);
1294 }
1295
1296
1297 /**
1298  * Changes the preferences for a peer in the problem
1299  *
1300  * @param solver the solver handle
1301  * @param client the client with this preference
1302  * @param peer the peer to change the preference for
1303  * @param kind the kind to change the preference
1304  * @param score the score
1305  */
1306 void
1307 GAS_simplistic_address_change_preference (void *solver,
1308                                    void *client,
1309                                    const struct GNUNET_PeerIdentity *peer,
1310                                    enum GNUNET_ATS_PreferenceKind kind,
1311                                    float score_f)
1312 {
1313   static struct GNUNET_TIME_Absolute next_update;
1314   struct GAS_SIMPLISTIC_Handle *s = solver;
1315   struct PreferenceClient *c_cur;
1316   struct PreferencePeer *p_cur;
1317   int i;
1318
1319   GNUNET_assert (NULL != solver);
1320   GNUNET_assert (NULL != client);
1321   GNUNET_assert (NULL != peer);
1322
1323   LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p changes preference for peer `%s' %s %f\n",
1324                                 client,
1325                                 GNUNET_i2s (peer),
1326                                 GNUNET_ATS_print_preference_type (kind),
1327                                 score_f);
1328
1329   if (kind >= GNUNET_ATS_PreferenceCount)
1330   {
1331       GNUNET_break (0);
1332       return;
1333   }
1334
1335   /* Find preference client */
1336   for (c_cur = s->pc_head; NULL != c_cur; c_cur = c_cur->next)
1337   {
1338       if (client == c_cur->client)
1339         break;
1340   }
1341   /* Not found: create new preference client */
1342   if (NULL == c_cur)
1343   {
1344     c_cur = GNUNET_malloc (sizeof (struct PreferenceClient));
1345     c_cur->client = client;
1346     GNUNET_CONTAINER_DLL_insert (s->pc_head, s->pc_tail, c_cur);
1347   }
1348
1349   /* Find entry for peer */
1350   for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
1351     if (0 == memcmp (&p_cur->id, peer, sizeof (p_cur->id)))
1352         break;
1353
1354   /* Not found: create new peer entry */
1355   if (NULL == p_cur)
1356   {
1357       p_cur = GNUNET_malloc (sizeof (struct PreferencePeer));
1358       p_cur->s = s;
1359       p_cur->client = c_cur;
1360       p_cur->id = (*peer);
1361       for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
1362       {
1363         /* Default value per peer absolut preference for a quality:
1364          * No value set, so absolute preference 0 */
1365         p_cur->f[i] = 0.0;
1366         /* Default value per peer relative preference for a quality: 1.0 */
1367         p_cur->f_rel[i] = DEFAULT_PREFERENCE;
1368       }
1369       p_cur->aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL, &preference_aging, p_cur);
1370       GNUNET_CONTAINER_DLL_insert (c_cur->p_head, c_cur->p_tail, p_cur);
1371   }
1372
1373   update_preference (p_cur, kind, score_f);
1374
1375   /* FIXME: We should update quotas if UPDATE_INTERVAL is reached */
1376   if (GNUNET_TIME_absolute_get().abs_value > next_update.abs_value)
1377   {
1378       /* update quotas*/
1379       next_update = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
1380                                               MIN_UPDATE_INTERVAL);
1381   }
1382 }
1383
1384 /* end of gnunet-service-ats_addresses_simplistic.c */