- change
[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 simplistic solver
36  *
37  * Assigns in and outbound bandwidth equally for all addresses in specific
38  * network type (WAN, LAN) based on configured in and outbound quota for this
39  * network.
40  *
41  * For each peer only a single is selected and marked as "active" in the address
42  * struct.
43  *
44  * E.g.:
45  *
46  * You have the networks WAN and LAN and quotas
47  * WAN_TOTAL_IN, WAN_TOTAL_OUT
48  * LAN_TOTAL_IN, LAN_TOTAL_OUT
49  *
50  * If you have x addresses in the network segment LAN, the quotas are
51  * QUOTA_PER_ADDRESS = LAN_TOTAL_OUT / x
52  *
53  * Quotas are automatically recalculated and reported back when addresses are
54  * - requested
55  *
56  */
57
58
59 /**
60  * A handle for the simplistic solver
61  */
62 struct GAS_SIMPLISTIC_Handle
63 {
64   /**
65    * Statistics handle
66    */
67
68   struct GNUNET_STATISTICS_Handle *stats;
69
70   /**
71    * Total number of addresses for solver
72    */
73   unsigned int total_addresses;
74
75   /**
76    * Number of active addresses for solver
77    */
78   unsigned int active_addresses;
79
80   /**
81    * Networks array
82    */
83   struct Network *network_entries;
84
85   /**
86    * Number of networks
87    */
88   unsigned int networks;
89
90   /**
91    * Callback
92    */
93   GAS_bandwidth_changed_cb bw_changed;
94
95   /**
96    * Callback cls
97    */
98   void *bw_changed_cls;
99
100   struct PreferenceClient *pc_head;
101   struct PreferenceClient *pc_tail;
102 };
103
104 struct Network
105 {
106   /**
107    * ATS network type
108    */
109   unsigned int type;
110
111   /**
112    * Network description
113    */
114   char *desc;
115
116   /**
117    * Total inbound quota
118    *
119    */
120   unsigned long long total_quota_in;
121
122   /**
123    * Total outbound quota
124    *
125    */
126   unsigned long long total_quota_out;
127
128   /**
129    * Number of active addresses for this network
130    */
131   unsigned int active_addresses;
132
133   /**
134    * Number of total addresses for this network
135    */
136   unsigned int total_addresses;
137
138   /**
139    * String for statistics total addresses
140    */
141   char *stat_total;
142
143   /**
144    * String for statistics active addresses
145    */
146   char *stat_active;
147
148   struct AddressWrapper *head;
149   struct AddressWrapper *tail;
150 };
151
152 struct AddressWrapper
153 {
154   struct AddressWrapper *next;
155   struct AddressWrapper *prev;
156
157   struct ATS_Address *addr;
158 };
159
160
161 struct PreferencePeer
162 {
163   struct PreferencePeer *next;
164   struct PreferencePeer *prev;
165   struct GNUNET_PeerIdentity id;
166
167   float f[GNUNET_ATS_PreferenceCount];
168   float f_rel[GNUNET_ATS_PreferenceCount];
169   float f_rel_total;
170 };
171
172 struct PreferenceClient
173 {
174   struct PreferenceClient *prev;
175   struct PreferenceClient *next;
176   void *client;
177
178   float f_total[GNUNET_ATS_PreferenceCount];
179
180   struct PreferencePeer *p_head;
181   struct PreferencePeer *p_tail;
182 };
183
184
185 /**
186  * Get the prefered address for a specific peer
187  *
188  * @param solver the solver handle
189  * @param addresses the address hashmap containing all addresses
190  * @param peer the identity of the peer
191  */
192 const struct ATS_Address *
193 GAS_simplistic_get_preferred_address (void *solver,
194                                struct GNUNET_CONTAINER_MultiHashMap * addresses,
195                                const struct GNUNET_PeerIdentity *peer);
196
197 /**
198  * Init the simplistic problem solving component
199  *
200  * Quotas:
201  * network[i] contains the network type as type GNUNET_ATS_NetworkType[i]
202  * out_quota[i] contains outbound quota for network type i
203  * in_quota[i] contains inbound quota for network type i
204  *
205  * Example
206  * network = {GNUNET_ATS_NET_UNSPECIFIED, GNUNET_ATS_NET_LOOPBACK, GNUNET_ATS_NET_LAN, GNUNET_ATS_NET_WAN, GNUNET_ATS_NET_WLAN}
207  * network[2]   == GNUNET_ATS_NET_LAN
208  * out_quota[2] == 65353
209  * in_quota[2]  == 65353
210  *
211  * @param cfg configuration handle
212  * @param stats the GNUNET_STATISTICS handle
213  * @param network array of GNUNET_ATS_NetworkType with length dest_length
214  * @param out_quota array of outbound quotas
215  * @param in_quota array of outbound quota
216  * @param dest_length array length for quota arrays
217  * @param bw_changed_cb callback for changed bandwidth amounts
218  * @param bw_changed_cb_cls cls for callback
219  * @return handle for the solver on success, NULL on fail
220  */
221 void *
222 GAS_simplistic_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
223                      const struct GNUNET_STATISTICS_Handle *stats,
224                      int *network,
225                      unsigned long long *out_quota,
226                      unsigned long long *in_quota,
227                      int dest_length,
228                      GAS_bandwidth_changed_cb bw_changed_cb,
229                      void *bw_changed_cb_cls)
230 {
231   int c;
232   struct GAS_SIMPLISTIC_Handle *s = GNUNET_malloc (sizeof (struct GAS_SIMPLISTIC_Handle));
233   struct Network * cur;
234   char * net_str[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkTypeString;
235
236
237   s->stats = (struct GNUNET_STATISTICS_Handle *) stats;
238   s->bw_changed = bw_changed_cb;
239   s->bw_changed_cls = bw_changed_cb_cls;
240   s->networks = dest_length;
241   s->network_entries = GNUNET_malloc (dest_length * sizeof (struct Network));
242   s->active_addresses = 0;
243   s->total_addresses = 0;
244
245   for (c = 0; c < dest_length; c++)
246   {
247       cur = &s->network_entries[c];
248       cur->total_addresses = 0;
249       cur->active_addresses = 0;
250       cur->type = network[c];
251       cur->total_quota_in = in_quota[c];
252       cur->total_quota_out = out_quota[c];
253       cur->desc = net_str[c];
254       GNUNET_asprintf (&cur->stat_total, "# ATS addresses %s total", cur->desc);
255       GNUNET_asprintf (&cur->stat_active, "# ATS active addresses %s total", cur->desc);
256   }
257   return s;
258 }
259
260 /**
261  * Shutdown the simplistic problem solving component
262  *
263  * @param solver the respective handle to shutdown
264  */
265 void
266 GAS_simplistic_done (void *solver)
267 {
268   struct GAS_SIMPLISTIC_Handle *s = solver;
269   struct PreferenceClient *pc;
270   struct PreferenceClient *next_pc;
271   struct PreferencePeer *p;
272   struct PreferencePeer *next_p;
273   struct AddressWrapper *cur;
274   struct AddressWrapper *next;
275   int c;
276   GNUNET_assert (s != NULL);
277
278   for (c = 0; c < s->networks; c++)
279   {
280       if (s->network_entries[c].total_addresses > 0)
281       {
282         LOG (GNUNET_ERROR_TYPE_ERROR,
283                     "Had %u addresses for network `%s' not deleted during shutdown\n",
284                     s->network_entries[c].total_addresses,
285                     s->network_entries[c].desc);
286         GNUNET_break (0);
287       }
288
289       if (s->network_entries[c].active_addresses > 0)
290       {
291         LOG (GNUNET_ERROR_TYPE_ERROR,
292                     "Had %u active addresses for network `%s' not deleted during shutdown\n",
293                     s->network_entries[c].active_addresses,
294                     s->network_entries[c].desc);
295         GNUNET_break (0);
296       }
297
298       next = s->network_entries[c].head;
299       while (NULL != (cur = next))
300       {
301           next = cur->next;
302           GNUNET_CONTAINER_DLL_remove (s->network_entries[c].head,
303                                        s->network_entries[c].tail,
304                                        cur);
305           GNUNET_free (cur);
306       }
307       GNUNET_free (s->network_entries[c].stat_total);
308       GNUNET_free (s->network_entries[c].stat_active);
309   }
310   if (s->total_addresses > 0)
311   {
312     LOG (GNUNET_ERROR_TYPE_ERROR,
313                 "Had %u addresses not deleted during shutdown\n",
314                 s->total_addresses);
315     GNUNET_break (0);
316   }
317   if (s->active_addresses > 0)
318   {
319     LOG (GNUNET_ERROR_TYPE_ERROR,
320                 "Had %u active addresses not deleted during shutdown\n",
321                 s->active_addresses);
322     GNUNET_break (0);
323   }
324   GNUNET_free (s->network_entries);
325
326   next_pc = s->pc_head;
327   while (NULL != (pc = next_pc))
328   {
329       next_pc = pc->next;
330       GNUNET_CONTAINER_DLL_remove (s->pc_head, s->pc_tail, pc);
331       next_p = pc->p_head;
332       while (NULL != (p = next_p))
333       {
334           next_p = p->next;
335           GNUNET_CONTAINER_DLL_remove (pc->p_head, pc->p_tail, p);
336           GNUNET_free (p);
337       }
338       GNUNET_free (pc);
339   }
340   GNUNET_free (s);
341 }
342
343 static unsigned long long int
344 calculate_new_quota (unsigned long long int total,
345                      unsigned int addresses)
346 {
347   return (total / addresses);
348 }
349
350 /**
351  * Test if bandwidth is available in this network
352  *
353  * @param s the solver handle
354  * @param net the network type to update
355  * @return GNUNET_YES or GNUNET_NO
356  */
357
358 static int
359 bw_available_in_network (struct Network *net)
360 {
361   unsigned int na = net->active_addresses + 1;
362   uint32_t min_bw = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
363   if (((net->total_quota_in / na) > min_bw) &&
364       ((net->total_quota_out / na) > min_bw))
365   {    
366     LOG (GNUNET_ERROR_TYPE_DEBUG,
367          "Enough bandwidth available for %u active addresses in network `%s'\n",
368          na,
369          net->desc);
370                                                                       
371     return GNUNET_YES;
372   }
373     LOG (GNUNET_ERROR_TYPE_DEBUG,
374          "Not enough bandwidth available for %u active addresses in network `%s'\n",
375          na,
376          net->desc);  
377   return GNUNET_NO;
378 }
379
380 /**
381  * Update the quotas for a network type
382  *
383  * @param s the solver handle
384  * @param net the network type to update
385  * @param address_except address excluded from notifcation, since we suggest
386  * this address
387  */
388 static void
389 update_quota_per_network (struct GAS_SIMPLISTIC_Handle *s,
390                           struct Network *net,
391                           struct ATS_Address *address_except)
392 {
393   unsigned long long quota_in = 0;
394   unsigned long long quota_out = 0;
395   struct AddressWrapper *cur;
396
397   LOG (GNUNET_ERROR_TYPE_DEBUG,
398               "Recalculate quota for network type `%s' for %u addresses (in/out): %llu/%llu \n",
399               net->desc, net->active_addresses, quota_in, quota_out);
400
401   if (net->active_addresses == 0)
402     return; /* no addresses to update */
403
404   quota_in = calculate_new_quota (net->total_quota_in, net->active_addresses);
405   quota_out = calculate_new_quota (net->total_quota_out, net->active_addresses);
406
407   LOG (GNUNET_ERROR_TYPE_DEBUG,
408               "New per address quota for network type `%s' for %u addresses (in/out): %llu/%llu \n",
409               net->desc, net->active_addresses, quota_in, quota_out);
410
411   cur = net->head;
412   while (NULL != cur)
413   {
414       /* Compare to current bandwidth assigned */
415       if ((quota_in != ntohl(cur->addr->assigned_bw_in.value__)) ||
416           (quota_out != ntohl(cur->addr->assigned_bw_out.value__)))
417       {
418         cur->addr->assigned_bw_in.value__ = htonl (quota_in);
419         cur->addr->assigned_bw_out.value__ = htonl (quota_out);
420         /* Notify on change */
421         if ((GNUNET_YES == cur->addr->active) && (cur->addr != address_except))
422           s->bw_changed (s->bw_changed_cls, cur->addr);
423       }
424       cur = cur->next;
425   }
426 }
427
428 static void
429 addresse_increment (struct GAS_SIMPLISTIC_Handle *s,
430                                 struct Network *net,
431                                 int total,
432                                 int active)
433 {
434   if (GNUNET_YES == total)
435   {
436       s->total_addresses ++;
437       net->total_addresses ++;
438       GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", 1, GNUNET_NO);
439       GNUNET_STATISTICS_update (s->stats, net->stat_total, 1, GNUNET_NO);
440   }
441   if (GNUNET_YES == active)
442   {
443     net->active_addresses ++;
444     s->active_addresses ++;
445     GNUNET_STATISTICS_update (s->stats, "# ATS active addresses total", 1, GNUNET_NO);
446     GNUNET_STATISTICS_update (s->stats, net->stat_active, 1, GNUNET_NO);
447   }
448
449 }
450
451 static int
452 addresse_decrement (struct GAS_SIMPLISTIC_Handle *s,
453                     struct Network *net,
454                     int total,
455                     int active)
456 {
457   int res = GNUNET_OK;
458   if (GNUNET_YES == total)
459   {
460     if (s->total_addresses < 1)
461     {
462       GNUNET_break (0);
463       res = GNUNET_SYSERR;
464     }
465     else
466     {
467       s->total_addresses --;
468       GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", -1, GNUNET_NO);
469     }
470     if (net->total_addresses < 1)
471     {
472       GNUNET_break (0);
473       res = GNUNET_SYSERR;
474     }
475     else
476     {
477       net->total_addresses --;
478       GNUNET_STATISTICS_update (s->stats, net->stat_total, -1, GNUNET_NO);
479     }
480   }
481
482   if (GNUNET_YES == active)
483   {
484     if (net->active_addresses < 1)
485     {
486       GNUNET_break (0);
487       res = GNUNET_SYSERR;
488     }
489     else
490     {
491       net->active_addresses --;
492       GNUNET_STATISTICS_update (s->stats, net->stat_active, -1, GNUNET_NO);
493     }
494     if (s->active_addresses < 1)
495     {
496       GNUNET_break (0);
497       res = GNUNET_SYSERR;
498     }
499     else
500     {
501       s->active_addresses --;
502       GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", -1, GNUNET_NO);
503     }
504   }
505   return res;
506 }
507
508
509 /**
510  * Add a single address to the solve
511  *
512  * @param solver the solver Handle
513  * @param addresses the address hashmap containing all addresses
514  * @param address the address to add
515  */
516 void
517 GAS_simplistic_address_add (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
518 {
519   struct GAS_SIMPLISTIC_Handle *s = solver;
520   struct Network *net = NULL;
521   struct AddressWrapper *aw = NULL;
522   GNUNET_assert (NULL != s);
523   int c;
524   for (c = 0; c < s->networks; c++)
525   {
526       net = &s->network_entries[c];
527       if (address->atsp_network_type == net->type)
528           break;
529   }
530   if (NULL == net)
531   {
532     GNUNET_break (0);
533     return;
534   }
535
536   aw = GNUNET_malloc (sizeof (struct AddressWrapper));
537   aw->addr = address;
538   GNUNET_CONTAINER_DLL_insert (net->head, net->tail, aw);
539   addresse_increment (s, net, GNUNET_YES, GNUNET_NO);
540   aw->addr->solver_information = net;
541
542
543   LOG (GNUNET_ERROR_TYPE_DEBUG, "After adding address now total %u and active %u addresses in network `%s'\n",
544       net->total_addresses,
545       net->active_addresses,
546       net->desc);
547 }
548
549 /**
550  * Remove an address from the solver
551  *
552  * @param solver the solver handle
553  * @param addresses the address hashmap containing all addresses
554  * @param address the address to remove
555  * @param session_only delete only session not whole address
556  */
557 void
558 GAS_simplistic_address_delete (void *solver,
559     struct GNUNET_CONTAINER_MultiHashMap * addresses,
560     struct ATS_Address *address, int session_only)
561 {
562   struct GAS_SIMPLISTIC_Handle *s = solver;
563   struct Network *net;
564   struct AddressWrapper *aw;
565
566   /* Remove an adress completely, we have to:
567    * - Remove from specific network
568    * - Decrease number of total addresses
569    * - If active:
570    *   - decrease number of active addreses
571    *   - update quotas
572    */
573
574   net = (struct Network *) address->solver_information;
575
576   if (GNUNET_NO == session_only)
577   {
578     LOG (GNUNET_ERROR_TYPE_DEBUG, "Deleting %s address %p for peer `%s' from network `%s' (total: %u/ active: %u)\n",
579         (GNUNET_NO == address->active) ? "inactive" : "active",
580         address, GNUNET_i2s (&address->peer),
581         net->desc, net->total_addresses, net->active_addresses);
582
583     /* Remove address */
584     addresse_decrement (s, net, GNUNET_YES, GNUNET_NO);
585     for (aw = net->head; NULL != aw; aw = aw->next)
586     {
587         if (aw->addr == address)
588           break;
589     }
590     if (NULL == aw )
591     {
592         GNUNET_break (0);
593         return;
594     }
595     GNUNET_CONTAINER_DLL_remove (net->head, net->tail, aw);
596     GNUNET_free (aw);
597   }
598   else
599   {
600       /* Remove session only: remove if active and update */
601       LOG (GNUNET_ERROR_TYPE_DEBUG, "Deleting %s session %p for peer `%s' from network `%s' (total: %u/ active: %u)\n",
602           (GNUNET_NO == address->active) ? "inactive" : "active",
603           address, GNUNET_i2s (&address->peer),
604           net->desc, net->total_addresses, net->active_addresses);
605   }
606
607   if (GNUNET_YES == address->active)
608   {
609       /* Address was active, remove from network and update quotas*/
610       address->active = GNUNET_NO;
611       if (GNUNET_SYSERR == addresse_decrement (s, net, GNUNET_NO, GNUNET_YES))
612         GNUNET_break (0);
613       update_quota_per_network (s, net, NULL);
614   }
615   LOG (GNUNET_ERROR_TYPE_DEBUG, "After deleting address now total %u and active %u addresses in network `%s'\n",
616       net->total_addresses,
617       net->active_addresses,
618       net->desc);
619
620 }
621
622 static struct Network *
623 find_network (struct GAS_SIMPLISTIC_Handle *s, uint32_t type)
624 {
625   int c;
626   for (c = 0 ; c < s->networks; c++)
627   {
628       if (s->network_entries[c].type == type)
629         return &s->network_entries[c];
630   }
631   return NULL;
632 }
633
634 /**
635  * Updates a single address in the solve
636  *
637  * @param solver the solver Handle
638  * @param addresses the address hashmap containing all addresses
639  * @param address the update address
640  * @param session the new session (if changed otherwise current)
641  * @param in_use the new address in use state (if changed otherwise current)
642  * @param atsi the latest ATS information
643  * @param atsi_count the atsi count
644  */
645 void
646 GAS_simplistic_address_update (void *solver,
647                               struct GNUNET_CONTAINER_MultiHashMap *addresses,
648                               struct ATS_Address *address,
649                               uint32_t session,
650                               int in_use,
651                               const struct GNUNET_ATS_Information *atsi,
652                               uint32_t atsi_count)
653 {
654   struct ATS_Address *new;
655   struct GAS_SIMPLISTIC_Handle *s = (struct GAS_SIMPLISTIC_Handle *) solver;
656   int i;
657   uint32_t value;
658   uint32_t type;
659   int save_active = GNUNET_NO;
660   struct Network *new_net = NULL;
661   for (i = 0; i < atsi_count; i++)
662   {
663     type = ntohl (atsi[i].type);
664     value = ntohl (atsi[i].value);
665     switch (type)
666     {
667     case GNUNET_ATS_UTILIZATION_UP:
668       //if (address->atsp_utilization_out.value__ != atsi[i].value)
669
670       break;
671     case GNUNET_ATS_UTILIZATION_DOWN:
672       //if (address->atsp_utilization_in.value__ != atsi[i].value)
673
674       break;
675     case GNUNET_ATS_QUALITY_NET_DELAY:
676       //if (address->atsp_latency.rel_value != value)
677
678       break;
679     case GNUNET_ATS_QUALITY_NET_DISTANCE:
680       //if (address->atsp_distance != value)
681
682       break;
683     case GNUNET_ATS_COST_WAN:
684       //if (address->atsp_cost_wan != value)
685
686       break;
687     case GNUNET_ATS_COST_LAN:
688       //if (address->atsp_cost_lan != value)
689
690       break;
691     case GNUNET_ATS_COST_WLAN:
692       //if (address->atsp_cost_wlan != value)
693
694       break;
695     case GNUNET_ATS_NETWORK_TYPE:
696       if (address->atsp_network_type != value)
697       {
698
699         LOG (GNUNET_ERROR_TYPE_DEBUG, "Network type changed, moving %s address from `%s' to `%s'\n",
700             (GNUNET_YES == address->active) ? "active" : "inactive",
701             GNUNET_ATS_print_network_type(address->atsp_network_type),
702             GNUNET_ATS_print_network_type(value));
703
704         save_active = address->active;
705         /* remove from old network */
706         GAS_simplistic_address_delete (solver, addresses, address, GNUNET_NO);
707
708         /* set new network type */
709         address->atsp_network_type = value;
710         new_net = find_network (solver, value);
711         address->solver_information = new_net;
712         if (address->solver_information == NULL)
713         {
714             GNUNET_break (0);
715             address->atsp_network_type = GNUNET_ATS_NET_UNSPECIFIED;
716             return;
717         }
718
719         /* Add to new network and update*/
720         GAS_simplistic_address_add (solver, addresses, address);
721         if (GNUNET_YES == save_active)
722         {
723           /* check if bandwidth available in new network */
724           if (GNUNET_YES == (bw_available_in_network (new_net)))
725           {
726               /* Suggest updated address */
727               address->active = GNUNET_YES;
728               addresse_increment (s, new_net, GNUNET_NO, GNUNET_YES);
729               update_quota_per_network (solver, new_net, NULL);
730           }
731           else
732           {
733             LOG (GNUNET_ERROR_TYPE_DEBUG, "Not enough bandwidth in new network, suggesting alternative address ..\n");
734
735             /* Set old address to zero bw */
736             address->assigned_bw_in = GNUNET_BANDWIDTH_value_init (0);
737             address->assigned_bw_out = GNUNET_BANDWIDTH_value_init (0);
738             s->bw_changed  (s->bw_changed_cls, address);
739
740             /* Find new address to suggest since no bandwidth in network*/
741             new = (struct ATS_Address *) GAS_simplistic_get_preferred_address (s, addresses, &address->peer);
742             if (NULL != new)
743             {
744                 /* Have an alternative address to suggest */
745                 s->bw_changed  (s->bw_changed_cls, new);
746             }
747
748           }
749         }
750       }
751       break;
752     case GNUNET_ATS_ARRAY_TERMINATOR:
753       break;
754     default:
755       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
756                   "Received unsupported ATS type %u\n", type);
757       GNUNET_break (0);
758       break;
759
760     }
761
762   }
763   if (address->session_id != session)
764   {
765       LOG (GNUNET_ERROR_TYPE_DEBUG,
766                   "Session changed from %u to %u\n", address->session_id, session);
767       address->session_id = session;
768   }
769   if (address->used != in_use)
770   {
771       LOG (GNUNET_ERROR_TYPE_DEBUG,
772                   "Usage changed from %u to %u\n", address->used, in_use);
773       address->used = in_use;
774   }
775
776 }
777
778
779
780 /**
781  * Find a "good" address to use for a peer.  If we already have an existing
782  * address, we stick to it.  Otherwise, we pick by lowest distance and then
783  * by lowest latency.
784  *
785  * @param cls the 'struct ATS_Address**' where we store the result
786  * @param key unused
787  * @param value another 'struct ATS_Address*' to consider using
788  * @return GNUNET_OK (continue to iterate)
789  */
790 static int
791 find_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
792 {
793   struct ATS_Address **previous_p = cls;
794   struct ATS_Address *current = (struct ATS_Address *) value;
795   struct ATS_Address *previous = *previous_p;
796   struct GNUNET_TIME_Absolute now;
797   struct Network *net = (struct Network *) current->solver_information;
798
799   now = GNUNET_TIME_absolute_get();
800
801   if (current->blocked_until.abs_value == GNUNET_TIME_absolute_max (now, current->blocked_until).abs_value)
802   {
803     /* This address is blocked for suggestion */
804     LOG (GNUNET_ERROR_TYPE_DEBUG,
805                 "Address %p blocked for suggestion for %llu ms \n",
806                 current,
807                 GNUNET_TIME_absolute_get_difference(now, current->blocked_until).rel_value);
808     return GNUNET_OK;
809   }
810
811   if (GNUNET_NO == bw_available_in_network (net))
812     return GNUNET_OK; /* There's no bandwidth available in this network */
813
814   if (NULL != previous)
815   {
816     if ((0 == strcmp (previous->plugin, "tcp")) &&
817         (0 == strcmp (current->plugin, "tcp")))
818     {
819       if ((0 != previous->addr_len) &&
820           (0 == current->addr_len))
821       {
822         /* saved address was an outbound address, but we have an inbound address */
823         *previous_p = current;
824         return GNUNET_OK;
825       }
826       if (0 == previous->addr_len)
827       {
828         /* saved address was an inbound address, so do not overwrite */
829         return GNUNET_OK;
830       }
831     }
832   }
833
834   if (NULL == previous)
835   {
836     *previous_p = current;
837     return GNUNET_OK;
838   }
839   if ((ntohl (previous->assigned_bw_in.value__) == 0) &&
840       (ntohl (current->assigned_bw_in.value__) > 0))
841   {
842     /* stick to existing connection */
843     *previous_p = current;
844     return GNUNET_OK;
845   }
846   if (previous->atsp_distance > current->atsp_distance)
847   {
848     /* user shorter distance */
849     *previous_p = current;
850     return GNUNET_OK;
851   }
852   if (previous->atsp_latency.rel_value > current->atsp_latency.rel_value)
853   {
854     /* user lower latency */
855     *previous_p = current;
856     return GNUNET_OK;
857   }
858   /* don't care */
859   return GNUNET_OK;
860 }
861
862 static int
863 find_active_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
864 {
865   struct ATS_Address * dest = (struct ATS_Address *) (*(struct ATS_Address **)cls);
866   struct ATS_Address * aa = (struct ATS_Address *) value;
867
868   if (GNUNET_YES == aa->active)
869   {
870       if (dest != NULL)
871       {
872           /* should never happen */
873           LOG (GNUNET_ERROR_TYPE_ERROR, "Multiple active addresses for peer `%s'\n", GNUNET_i2s (&aa->peer));
874           GNUNET_break (0);
875           return GNUNET_NO;
876       }
877       dest = aa;
878   }
879   return GNUNET_OK;
880 }
881
882 static struct ATS_Address *
883 find_active_address (void *solver,
884                      struct GNUNET_CONTAINER_MultiHashMap * addresses,
885                      const struct GNUNET_PeerIdentity *peer)
886 {
887   struct ATS_Address * dest = NULL;
888
889   GNUNET_CONTAINER_multihashmap_get_multiple(addresses,
890        &peer->hashPubKey,
891        &find_active_address_it, &dest);
892   return dest;
893 }
894
895 /**
896  * Get the prefered address for a specific peer
897  *
898  * @param solver the solver handle
899  * @param addresses the address hashmap containing all addresses
900  * @param peer the identity of the peer
901  */
902 const struct ATS_Address *
903 GAS_simplistic_get_preferred_address (void *solver,
904                                struct GNUNET_CONTAINER_MultiHashMap * addresses,
905                                const struct GNUNET_PeerIdentity *peer)
906 {
907   struct GAS_SIMPLISTIC_Handle *s = solver;
908   struct Network *net_prev;
909   struct Network *net_cur;
910   struct ATS_Address *cur;
911   struct ATS_Address *prev;
912
913   GNUNET_assert (s != NULL);
914   cur = NULL;
915   /* Get address with: stick to current address, lower distance, lower latency */
916   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
917                                               &find_address_it, &cur);
918   if (NULL == cur)
919   {
920     LOG (GNUNET_ERROR_TYPE_DEBUG, "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
921     return NULL;
922   }
923
924   LOG (GNUNET_ERROR_TYPE_DEBUG, "Suggesting %s address %p for peer `%s'\n",
925       (GNUNET_NO == cur->active) ? "inactive" : "active",
926       cur, GNUNET_i2s (peer));
927   net_cur = (struct Network *) cur->solver_information;
928   if (GNUNET_YES == cur->active)
929   {
930       /* This address was selected previously, so no need to update quotas */
931       return cur;
932   }
933
934   /* This address was not active, so we have to:
935    *
936    * - mark previous active address as not active
937    * - update quota for previous address network
938    * - update quota for this address network
939    */
940
941   prev = find_active_address (s, addresses, peer);
942   if (NULL != prev)
943   {
944       net_prev = (struct Network *) prev->solver_information;
945       prev->active = GNUNET_NO; /* No active any longer */
946       prev->assigned_bw_in = GNUNET_BANDWIDTH_value_init (0); /* no bw assigned */
947       prev->assigned_bw_out = GNUNET_BANDWIDTH_value_init (0); /* no bw assigned */
948       s->bw_changed (s->bw_changed_cls, prev); /* notify about bw change, REQUIRED? */
949       if (GNUNET_SYSERR == addresse_decrement (s, net_prev, GNUNET_NO, GNUNET_YES))
950         GNUNET_break (0);
951       update_quota_per_network (s, net_prev, NULL);
952   }
953
954   if (GNUNET_NO == (bw_available_in_network (cur->solver_information)))
955   {
956     GNUNET_break (0); /* This should never happen*/
957     return NULL;
958   }
959
960   cur->active = GNUNET_YES;
961   addresse_increment(s, net_cur, GNUNET_NO, GNUNET_YES);
962   update_quota_per_network (s, net_cur, cur);
963
964   return cur;
965 }
966
967 /**
968  * Changes the preferences for a peer in the problem
969  *
970  * @param solver the solver handle
971  * @param client the client with this preference
972  * @param peer the peer to change the preference for
973  * @param kind the kind to change the preference
974  * @param score the score
975  */
976 void
977 GAS_simplistic_address_change_preference (void *solver,
978                                    void *client,
979                                    const struct GNUNET_PeerIdentity *peer,
980                                    enum GNUNET_ATS_PreferenceKind kind,
981                                    float score)
982 {
983   struct GAS_SIMPLISTIC_Handle *s = solver;
984   struct PreferenceClient *cur;
985   struct PreferencePeer *p;
986   int i;
987
988   GNUNET_assert (NULL != solver);
989   GNUNET_assert (NULL != client);
990   GNUNET_assert (NULL != peer);
991
992   /**
993    * Idea:
994    *
995    * We have:
996    * Set of clients c
997    * Set of peers p_i in P
998    * Set of preference kinds k
999    * A preference value f_k_p_i with an unknown range
1000    *
1001    * We get:
1002    * A client specific relative preference f_p_i_rel [1..2] for all peers
1003    *
1004    * For every client c
1005    * {
1006    *   For every preference kind k:
1007    *   {
1008    *     We remember for the preference f_p_i for each peer p_i.
1009    *     We have a default preference value f_p_i = 0
1010    *     We have a sum of all preferences f_t = sum (f_p_i)
1011    *     So we can calculate a relative preference value fr_p_i:
1012    *
1013    *     f_k_p_i_rel = (f_t + f_p_i) / f_t
1014    *     f_k_p_i_rel = [1..2]
1015    *    }
1016    *    f_p_i_rel = sum (f_k_p_i_rel) / #k
1017    * }
1018    *
1019    **/
1020
1021   LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p changes preference for peer `%s' %s %f\n",
1022                                 client,
1023                                 GNUNET_i2s (peer),
1024                                 GNUNET_ATS_print_preference_type (kind),
1025                                 score);
1026
1027   if (kind >= GNUNET_ATS_PreferenceCount)
1028   {
1029       GNUNET_break (0);
1030       return;
1031   }
1032
1033   for (cur = s->pc_head; NULL != cur; cur = cur->next)
1034   {
1035       if (client == cur->client)
1036         break;
1037   }
1038   if (NULL == cur)
1039   {
1040     cur = GNUNET_malloc (sizeof (struct PreferenceClient));
1041     cur->client = client;
1042     GNUNET_CONTAINER_DLL_insert (s->pc_head, s->pc_tail, cur);
1043   }
1044
1045   for (p = cur->p_head; NULL != p; p = p->next)
1046     if (0 == memcmp (&p->id, peer, sizeof (p->id)))
1047         break;
1048
1049   if (NULL == p)
1050   {
1051       /* Add a new peer entry */
1052       p = GNUNET_malloc (sizeof (struct PreferencePeer));
1053       p->id = (*peer);
1054       for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
1055       {
1056         p->f[i] = 0.0;
1057         p->f_rel[i] = 1.0;
1058       }
1059       GNUNET_CONTAINER_DLL_insert (cur->p_head, cur->p_tail, p);
1060   }
1061
1062   switch (kind) {
1063     case GNUNET_ATS_PREFERENCE_BANDWIDTH:
1064     case GNUNET_ATS_PREFERENCE_LATENCY:
1065       p->f[kind] = (p->f[kind] + score) / 2;
1066       break;
1067     case GNUNET_ATS_PREFERENCE_END:
1068       break;
1069     default:
1070       break;
1071   }
1072   /* Recalcalculate total preference for kind*/
1073   cur->f_total[kind] = 0;
1074   for (p = cur->p_head; NULL != p; p = p->next)
1075     cur->f_total[kind] += p->f[kind];
1076
1077   LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p has total preference for %s of %f\n",
1078       cur,
1079       GNUNET_ATS_print_preference_type (kind),
1080       cur->f_total[kind]);
1081
1082   /* Recalcalculate relative preference */
1083   for (p = cur->p_head; NULL != p; p = p->next)
1084   {
1085     /* Calculate relative preference for specific kind */
1086     p->f_rel[kind] = (cur->f_total[kind] + p->f[kind]) / cur->f_total[kind];
1087     LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p: peer `%s' has relative preference for %s of %f\n",
1088         cur,
1089         GNUNET_i2s (&p->id),
1090         GNUNET_ATS_print_preference_type (kind),
1091         p->f_rel[kind]);
1092
1093     /* Calculate peer relative preference
1094      * Start with i = 1 to exclude terminator */
1095     p->f_rel_total = 0;
1096     for (i = 1; i < GNUNET_ATS_PreferenceCount; i ++)
1097     {
1098         p->f_rel_total += p->f_rel[i];
1099     }
1100     p->f_rel_total /=  GNUNET_ATS_PreferenceCount - 1.0;
1101     LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p: peer `%s' has total relative preference of %f\n",
1102         cur,
1103         GNUNET_i2s (&p->id),
1104         p->f_rel_total);
1105   }
1106 }
1107
1108 /* end of gnunet-service-ats_addresses_simplistic.c */