fix coverity 10390
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses.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.c
23  * @brief ats service address management
24  * @author Matthias Wachs
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_ats_service.h"
29 #include "gnunet-service-ats.h"
30 #include "gnunet-service-ats_addresses.h"
31 #include "gnunet-service-ats_performance.h"
32 #include "gnunet-service-ats_scheduling.h"
33 #include "gnunet-service-ats_reservations.h"
34 #if HAVE_LIBGLPK
35 #include "gnunet-service-ats_addresses_mlp.h"
36 #endif
37 #include "gnunet-service-ats_addresses_simplistic.h"
38
39 /**
40  * ATS address management
41  *
42  * Adding addresses:
43  *
44  * - If you add a new address without a session, a new address will be added
45  * - If you add this address again now with a session a, the existing address
46  *   will be updated with this session
47  * - If you add this address again now with a session b, a new address object
48  *   with this session will be added
49
50  * Destroying addresses:
51  *
52  * - If you destroy an address without a session, the address itself and all
53  *   address instances with an session will be removed
54  * - If you destroy an address with a session, the session for this address
55  *   will be removed
56  *
57  * Conclusion
58  * Addresses without a session will be updated with a new session and if the
59  * the session is destroyed the session is removed and address itself still
60  * exists for suggestion
61  *
62  */
63
64
65 /**
66  * Available ressource assignment modes
67  */
68 enum ATS_Mode
69 {
70   /*
71    * Simplistic mode:
72    *
73    * Assign each peer an equal amount of bandwidth (bw)
74    *
75    * bw_per_peer = bw_total / #active addresses
76    */
77   MODE_SIMPLISTIC,
78
79   /*
80    * MLP mode:
81    *
82    * Solve ressource assignment as an optimization problem
83    * Uses an mixed integer programming solver
84    */
85   MODE_MLP
86 };
87
88 /**
89  * Handle for ATS address component
90  */
91 struct GAS_Addresses_Suggestion_Requests
92 {
93   struct GAS_Addresses_Suggestion_Requests *next;
94   struct GAS_Addresses_Suggestion_Requests *prev;
95
96   struct GNUNET_PeerIdentity id;
97 };
98
99 /**
100  * Handle for ATS address component
101  */
102 struct GAS_Addresses_Handle
103 {
104   /**
105    * A multihashmap to store all addresses
106    */
107   struct GNUNET_CONTAINER_MultiHashMap *addresses;
108
109   /**
110    * Configure WAN quota in
111    */
112   unsigned long long wan_quota_in;
113
114   /**
115    * Configure WAN quota out
116    */
117   unsigned long long wan_quota_out;
118
119   /**
120    * Is ATS addresses running
121    */
122   int running;
123
124   /**
125    * Configured ATS solver
126    */
127   int ats_mode;
128
129   /**
130    *  Solver handle
131    */
132   void *solver;
133
134   /**
135    * Address suggestion requests DLL head
136    */
137   struct GAS_Addresses_Suggestion_Requests *r_head;
138
139   /**
140    * Address suggestion requests DLL tail
141    */
142   struct GAS_Addresses_Suggestion_Requests *r_tail;
143
144   /* Solver functions */
145
146   /**
147    * Initialize solver
148    */
149   GAS_solver_init s_init;
150
151   /**
152    * Add an address to the solver
153    */
154   GAS_solver_address_add s_add;
155
156   /**
157    * Update address in solver
158    */
159   GAS_solver_address_update s_update;
160
161   /**
162    * Get address from solver
163    */
164   GAS_solver_get_preferred_address s_get;
165
166   /**
167    * Delete address in solver
168    */
169   GAS_solver_address_delete s_del;
170
171   /**
172    * Change preference for quality in solver
173    */
174   GAS_solver_address_change_preference s_pref;
175
176   /**
177    * Shutdown solver
178    */
179   GAS_solver_done s_done;
180 };
181
182
183 /**
184  * Temporary handle
185  */
186 struct GAS_Addresses_Handle *handle;
187
188
189 static unsigned int
190 assemble_ats_information (const struct ATS_Address *aa,  struct GNUNET_ATS_Information **dest)
191 {
192   unsigned int ats_count = GNUNET_ATS_PropertyCount - 1;
193   struct GNUNET_ATS_Information *ats = GNUNET_malloc (ats_count * sizeof (struct GNUNET_ATS_Information));
194   (*dest) = ats;
195
196   ats[0].type = ntohl(GNUNET_ATS_UTILIZATION_UP);
197   ats[0].value = aa->atsp_utilization_out.value__;
198   ats[1].type = ntohl(GNUNET_ATS_UTILIZATION_DOWN);
199   ats[1].value = aa->atsp_utilization_in.value__;
200   ats[2].type = ntohl(GNUNET_ATS_NETWORK_TYPE);
201   ats[2].value = ntohl(aa->atsp_network_type);
202   ats[3].type = ntohl(GNUNET_ATS_QUALITY_NET_DELAY);
203   ats[3].value = ntohl(aa->atsp_latency.rel_value);
204   ats[4].type = ntohl(GNUNET_ATS_QUALITY_NET_DISTANCE);
205   ats[4].value = ntohl(aa->atsp_distance);
206   ats[5].type = ntohl(GNUNET_ATS_COST_WAN);
207   ats[5].value = ntohl (aa->atsp_cost_wan);
208   ats[6].type = ntohl(GNUNET_ATS_COST_LAN);
209   ats[6].value = ntohl (aa->atsp_cost_lan);
210   ats[7].type = ntohl(GNUNET_ATS_COST_WLAN);
211   ats[7].value = ntohl (aa->atsp_cost_wlan);
212   return ats_count;
213 }
214
215 static unsigned int
216 disassemble_ats_information (const struct GNUNET_ATS_Information *src,
217                              uint32_t ats_count,
218                              struct ATS_Address *dest)
219 {
220   int i;
221   int res = 0;
222   for (i = 0; i < ats_count; i++)
223     switch (ntohl (src[i].type))
224     {
225     case GNUNET_ATS_UTILIZATION_UP:
226       dest->atsp_utilization_out.value__ = src[i].value;
227       res ++;
228       break;
229     case GNUNET_ATS_UTILIZATION_DOWN:
230       dest->atsp_utilization_in.value__ = src[i].value;
231       res ++;
232       break;
233     case GNUNET_ATS_QUALITY_NET_DELAY:
234       dest->atsp_latency.rel_value = ntohl (src[i].value);
235       res ++;
236       break;
237     case GNUNET_ATS_QUALITY_NET_DISTANCE:
238       dest->atsp_distance = ntohl (src[i].value);
239       res ++;
240       break;
241     case GNUNET_ATS_COST_WAN:
242       dest->atsp_cost_wan = ntohl (src[i].value);
243       res ++;
244       break;
245     case GNUNET_ATS_COST_LAN:
246       dest->atsp_cost_lan = ntohl (src[i].value);
247       res ++;
248       break;
249     case GNUNET_ATS_COST_WLAN:
250       dest->atsp_cost_wlan = ntohl (src[i].value);
251       res ++;
252       break;
253     case GNUNET_ATS_NETWORK_TYPE:
254       dest->atsp_network_type = ntohl (src[i].value);
255       res ++;
256       break;
257     case GNUNET_ATS_ARRAY_TERMINATOR:
258       break;
259     default:
260       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
261                   "Received unsupported ATS type %u\n", ntohl (src[i].type));
262       GNUNET_break (0);
263       break;
264     }
265   return res;
266 }
267
268 /**
269  * Free the given address
270  * @param addr address to destroy
271  */
272 static void
273 free_address (struct ATS_Address *addr)
274 {
275   GNUNET_free (addr->plugin);
276   GNUNET_free (addr);
277 }
278
279 /**
280  * Create a ATS_address with the given information
281  * @param peer peer
282  * @param plugin_name plugin
283  * @param plugin_addr address
284  * @param plugin_addr_len address length
285  * @param session_id session
286  * @return the ATS_Address
287  */
288 static struct ATS_Address *
289 create_address (const struct GNUNET_PeerIdentity *peer,
290                 const char *plugin_name,
291                 const void *plugin_addr, size_t plugin_addr_len,
292                 uint32_t session_id)
293 {
294   struct ATS_Address *aa = NULL;
295
296   aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
297   aa->peer = *peer;
298   aa->addr_len = plugin_addr_len;
299   aa->addr = &aa[1];
300   memcpy (&aa[1], plugin_addr, plugin_addr_len);
301   aa->plugin = GNUNET_strdup (plugin_name);
302   aa->session_id = session_id;
303   aa->active = GNUNET_NO;
304   aa->solver_information = NULL;
305   aa->assigned_bw_in = GNUNET_BANDWIDTH_value_init(0);
306   aa->assigned_bw_out = GNUNET_BANDWIDTH_value_init(0);
307   return aa;
308 }
309
310
311 /**
312  * Destroy the given address.
313  *
314  * @param addr address to destroy
315  * @return GNUNET_YES if bandwidth allocations should be recalcualted
316  */
317 static int
318 destroy_address (struct ATS_Address *addr)
319 {
320   int ret;
321
322   ret = GNUNET_NO;
323   GNUNET_assert (GNUNET_YES ==
324                  GNUNET_CONTAINER_multihashmap_remove (handle->addresses,
325                                                        &addr->peer.hashPubKey,
326                                                        addr));
327   free_address (addr);
328   return ret;
329 }
330
331
332 struct CompareAddressContext
333 {
334   const struct ATS_Address *search;
335
336   /* exact_address != NULL if address and session is equal */
337   struct ATS_Address *exact_address;
338   /* exact_address != NULL if address and session is 0 */
339   struct ATS_Address *base_address;
340 };
341
342
343 static int
344 compare_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
345 {
346   struct CompareAddressContext *cac = cls;
347   struct ATS_Address *aa = value;
348
349   /* Find an matching exact address:
350    *
351    * Compare by:
352    * aa->addr_len == cac->search->addr_len
353    * aa->plugin == cac->search->plugin
354    * aa->addr == cac->search->addr
355    * aa->session == cac->search->session
356    *
357    * return as exact address
358    */
359   if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
360   {
361       if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id))
362         cac->exact_address = aa;
363   }
364
365   /* Find an matching base address:
366    *
367    * Properties:
368    *
369    * aa->session_id == 0
370    *
371    * Compare by:
372    * aa->addr_len == cac->search->addr_len
373    * aa->plugin == cac->search->plugin
374    * aa->addr == cac->search->addr
375    *
376    * return as base address
377    */
378   if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
379   {
380       if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == 0))
381         cac->base_address = aa;
382   }
383
384   /* Find an matching exact address based on session:
385    *
386    * Properties:
387    *
388    * cac->search->addr_len == 0
389    *
390    * Compare by:
391    * aa->plugin == cac->search->plugin
392    * aa->session_id == cac->search->session_id
393    *
394    * return as exact address
395    */
396   if (0 == cac->search->addr_len)
397   {
398       if ((0 == strcmp (aa->plugin, cac->search->plugin)) && (aa->session_id == cac->search->session_id))
399         cac->exact_address = aa;
400   }
401
402   if (cac->exact_address == NULL)
403     return GNUNET_YES; /* Continue iteration to find exact address */
404   else
405     return GNUNET_NO; /* Stop iteration since we have an exact address */
406 }
407
408
409 /**
410  * Find an existing equivalent address record.
411  * Compares by peer identity and network address OR by session ID
412  * (one of the two must match).
413  *
414  * @param peer peer to lookup addresses for
415  * @param addr existing address record
416  * @return existing address record, NULL for none
417  */
418 struct ATS_Address *
419 find_equivalent_address (const struct GNUNET_PeerIdentity *peer,
420               const struct ATS_Address *addr)
421 {
422   struct CompareAddressContext cac;
423
424   cac.exact_address = NULL;
425   cac.base_address = NULL;
426   cac.search = addr;
427   GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses, &peer->hashPubKey,
428                                               &compare_address_it, &cac);
429
430   if (cac.exact_address == NULL)
431     return cac.base_address;
432   return cac.exact_address;
433 }
434
435
436 static struct ATS_Address *
437 lookup_address (const struct GNUNET_PeerIdentity *peer,
438                 const char *plugin_name,
439                 const void *plugin_addr,
440                 size_t plugin_addr_len,
441                 uint32_t session_id,
442                 const struct GNUNET_ATS_Information *atsi,
443                 uint32_t atsi_count)
444 {
445   struct ATS_Address *aa;
446   struct ATS_Address *ea;
447
448   aa = create_address (peer,
449                        plugin_name,
450                        plugin_addr, plugin_addr_len,
451                        session_id);
452
453   /* Get existing address or address with session == 0 */
454   ea = find_equivalent_address (peer, aa);
455   free_address (aa);
456   if (ea == NULL)
457   {
458     return NULL;
459   }
460   else if (ea->session_id != session_id)
461   {
462     return NULL;
463   }
464   return ea;
465 }
466
467
468 void
469 GAS_addresses_add (const struct GNUNET_PeerIdentity *peer,
470                       const char *plugin_name, const void *plugin_addr,
471                       size_t plugin_addr_len, uint32_t session_id,
472                       const struct GNUNET_ATS_Information *atsi,
473                       uint32_t atsi_count)
474 {
475   struct ATS_Address *aa;
476   struct ATS_Address *ea;
477   unsigned int ats_res;
478
479   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
480               "Received `%s' for peer `%s'\n",
481               "ADDRESS ADD",
482               GNUNET_i2s (peer));
483
484   if (GNUNET_NO == handle->running)
485     return;
486
487   GNUNET_assert (NULL != handle->addresses);
488
489   aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len,
490                        session_id);
491   if (atsi_count != (ats_res = disassemble_ats_information(atsi, atsi_count, aa)))
492   {
493       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
494                 "While adding address: had %u ATS elements to add, could only add %u\n",
495                 atsi_count, ats_res);
496   }
497
498   /* Get existing address or address with session == 0 */
499   ea = find_equivalent_address (peer, aa);
500   if (ea == NULL)
501   {
502     /* We have a new address */
503     GNUNET_assert (GNUNET_OK ==
504                    GNUNET_CONTAINER_multihashmap_put (handle->addresses,
505                                                       &peer->hashPubKey, aa,
506                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
507     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added new address for peer `%s' session id %u, %p\n",
508                 GNUNET_i2s (peer), session_id, aa);
509     /* Tell solver about new address */
510     handle->s_add (handle->solver, handle->addresses, aa);
511     return;
512   }
513   GNUNET_free (aa->plugin);
514   GNUNET_free (aa);
515
516   if (ea->session_id != 0)
517   {
518       /* This addresswith the same session is already existing */
519       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
520                 "Added already existing address for peer `%s' `%s' %p with new session %u\n",
521                 GNUNET_i2s (peer), plugin_name, session_id);
522       GNUNET_break (0);
523       return;
524   }
525
526   /* We have an address without an session, update this address */
527   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
528             "Updated existing address for peer `%s' %p with new session %u\n",
529             GNUNET_i2s (peer), ea, session_id);
530   ea->session_id = session_id;
531   if (atsi_count != (ats_res = disassemble_ats_information(atsi, atsi_count, ea)))
532   {
533       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
534                 "While updating address: had %u ATS elements to add, could only add %u\n",
535                 atsi_count, ats_res);
536   }
537
538   handle->s_update (handle->solver, handle->addresses, ea);
539 }
540
541
542 void
543 GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
544                       const char *plugin_name, const void *plugin_addr,
545                       size_t plugin_addr_len, uint32_t session_id,
546                       const struct GNUNET_ATS_Information *atsi,
547                       uint32_t atsi_count)
548 {
549   struct ATS_Address *aa;
550   uint32_t ats_res;
551
552   if (GNUNET_NO == handle->running)
553     return;
554
555   GNUNET_assert (NULL != handle->addresses);
556
557   /* Get existing address */
558   aa = lookup_address (peer, plugin_name, plugin_addr, plugin_addr_len,
559                        session_id, atsi, atsi_count);
560   if (aa == NULL)
561   {
562     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Tried to update unknown address for peer `%s' `%s' session id %u\n",
563                 GNUNET_i2s (peer), plugin_name, session_id);
564     GNUNET_break (0);
565     return;
566   }
567
568   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
569                 "Received `%s' for peer `%s' address \n",
570                 "ADDRESS UPDATE",
571                 GNUNET_i2s (peer), aa);
572
573   if (atsi_count != (ats_res = disassemble_ats_information (atsi, atsi_count, aa)))
574   {
575       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576                 "While adding address: had %u ATS elements to add, could only add %u\n",
577                 atsi_count, ats_res);
578   }
579   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
580             "Updated %u ATS elements for address %p\n",
581             ats_res, aa);
582
583   /* Tell solver about update */
584   handle->s_update (handle->solver, handle->addresses, aa);
585 }
586
587
588 struct DestroyContext
589 {
590   struct ATS_Address *aa;
591
592   struct GAS_Addresses_Handle *handle;
593
594   /**
595    * GNUNET_NO  : full address
596    * GNUNET_YES : just session
597    */
598   int result;
599 };
600
601
602 /**
603  * Delete an address
604  *
605  * If session != 0, just the session is deleted, the address itself still exists
606  * If session == 0, remove full address
607  * If session == 0 and addrlen == 0, destroy inbound address
608  *
609  * @param cls unused
610  * @param key unused
611  * @param value the 'struct ATS_Address'
612  * @return GNUNET_OK (continue to iterate)
613  */
614 static int
615 destroy_by_session_id (void *cls, const struct GNUNET_HashCode * key, void *value)
616 {
617   struct DestroyContext *dc = cls;
618   struct GAS_Addresses_Handle *handle = dc->handle;
619   const struct ATS_Address *des = dc->aa;
620   struct ATS_Address *aa = value;
621
622   GNUNET_assert (0 == memcmp (&aa->peer, &des->peer,
623                               sizeof (struct GNUNET_PeerIdentity)));
624
625
626   if (des->session_id == 0)
627   {
628     /* Session == 0, remove full address  */
629     if ((0 == strcmp (des->plugin, aa->plugin)) &&
630         (aa->addr_len == des->addr_len) &&
631         (0 == memcmp (des->addr, aa->addr, aa->addr_len)))
632     {
633
634       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
635                   "Deleting full address for peer `%s' session %u %p\n",
636                   GNUNET_i2s (&aa->peer), aa->session_id, aa);
637
638       /* Notify solver about deletion */
639       handle->s_del (handle->solver, handle->addresses, aa, GNUNET_NO);
640       destroy_address (aa);
641       dc->result = GNUNET_NO;
642       return GNUNET_OK; /* Continue iteration */
643     }
644   }
645   else
646   {
647     /* Session != 0, just remove session */
648     if (aa->session_id != des->session_id)
649       return GNUNET_OK; /* irrelevant */
650
651     if ((aa->session_id != 0) &&
652         (0 != strcmp (des->plugin, aa->plugin)))
653     {
654         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
655                     "Different plugins during removal: `%s' vs `%s' \n",
656                     des->plugin, aa->plugin);
657         GNUNET_break (0);
658         return GNUNET_OK;
659     }
660
661     if (aa->addr_len == 0)
662     {
663         /* Inbound connection died, delete full address */
664         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
665                     "Deleting inbound address for peer `%s': `%s' session %u\n",
666                     GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
667
668         /* Notify solver about deletion */
669         handle->s_del (handle->solver, handle->addresses, aa, GNUNET_NO);
670         destroy_address (aa);
671         dc->result = GNUNET_NO;
672         return GNUNET_OK; /* Continue iteration */
673     }
674     else
675     {
676         /* Session died */
677         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
678                     "Deleting session for peer `%s': `%s' %u\n",
679                     GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
680         /* Notify solver to delete session */
681         handle->s_del (handle->solver, handle->addresses, aa, GNUNET_YES);
682         aa->session_id = 0;
683         return GNUNET_OK;
684     }
685   }
686   return GNUNET_OK;
687 }
688
689 void
690 GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
691                        const char *plugin_name, const void *plugin_addr,
692                        size_t plugin_addr_len, uint32_t session_id)
693 {
694   struct ATS_Address *ea;
695   struct DestroyContext dc;
696
697   if (GNUNET_NO == handle->running)
698     return;
699
700   /* Get existing address */
701   ea = lookup_address (peer, plugin_name, plugin_addr, plugin_addr_len,
702                        session_id, NULL, 0);
703
704   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
705               "Received `%s' for peer `%s' address %p session %u\n",
706               "ADDRESS DESTROY",
707               GNUNET_i2s (peer), ea, session_id);
708
709   if (ea == NULL)
710   {
711     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Tried to destroy unknown address for peer `%s' `%s' session id %u\n",
712                 GNUNET_i2s (peer), plugin_name, session_id);
713     return;
714   }
715
716   GNUNET_break (0 < strlen (plugin_name));
717   dc.handle = handle;
718   dc.aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id);
719
720   GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses, &peer->hashPubKey,
721                                               &destroy_by_session_id, &dc);
722   free_address (dc.aa);
723 }
724
725
726 int
727 GAS_addresses_in_use (const struct GNUNET_PeerIdentity *peer,
728                       const char *plugin_name, const void *plugin_addr,
729                       size_t plugin_addr_len, uint32_t session_id, int in_use)
730 {
731   struct ATS_Address *old;
732
733   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
734                 "Received `%s' for peer `%s'\n",
735                 "ADDRESS IN USE",
736                 GNUNET_i2s (peer));
737
738   if (GNUNET_NO == handle->running)
739     return GNUNET_SYSERR;
740
741   old = lookup_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id, NULL, 0);
742   if (NULL == old)
743   {
744     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
745                 "Trying to set unknown address `%s', %s %u %s \n",
746                 GNUNET_i2s (peer),
747                 plugin_name, session_id,
748                 (GNUNET_NO == in_use) ? "NO" : "YES");
749     GNUNET_break (0);
750     return GNUNET_SYSERR;
751   }
752   if (old->used == in_use)
753   {
754     GNUNET_break (0);
755     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
756                 "Address in use called multiple times for peer `%s': %s -> %s \n",
757                 GNUNET_i2s (peer),
758                 (GNUNET_NO == old->used) ? "NO" : "YES",
759                 (GNUNET_NO == in_use) ? "NO" : "YES");
760     return GNUNET_SYSERR;
761   }
762   old->used = in_use;
763
764   /* Tell solver about update */
765   handle->s_update (handle->solver, handle->addresses, old);
766
767   return GNUNET_OK;
768 }
769
770
771 /**
772  * Cancel address suggestions for a peer
773  *
774  * @param peer the respective peer
775  */
776 void
777 GAS_addresses_request_address_cancel (const struct GNUNET_PeerIdentity *peer)
778 {
779   struct GAS_Addresses_Suggestion_Requests *cur = handle->r_head;
780
781   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
782               "Received request: `%s' for peer %s\n", "request_address_cancel", GNUNET_i2s (peer));
783
784   while (NULL != cur)
785   {
786       if (0 == memcmp (peer, &cur->id, sizeof (cur->id)))
787         break; /* found */
788       cur = cur->next;
789   }
790
791   if (NULL == cur)
792   {
793       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
794                   "No address requests pending for peer `%s', cannot remove!\n", GNUNET_i2s (peer));
795       return;
796   }
797   GAS_addresses_handle_backoff_reset (peer);
798   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
799               "Removed request pending for peer `%s\n", GNUNET_i2s (peer));
800   GNUNET_CONTAINER_DLL_remove (handle->r_head, handle->r_tail, cur);
801   GNUNET_free (cur);
802 }
803
804
805 /**
806  * Add an address suggestions for a peer
807  *
808  * @param peer the respective peer
809  */
810 void
811 GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer)
812 {
813   struct GAS_Addresses_Suggestion_Requests *cur = handle->r_head;
814   struct ATS_Address *aa;
815   struct GNUNET_ATS_Information *ats;
816   unsigned int ats_count;
817
818   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
819               "Received `%s' for peer `%s'\n",
820               "REQUEST ADDRESS",
821               GNUNET_i2s (peer));
822
823   if (GNUNET_NO == handle->running)
824     return;
825   while (NULL != cur)
826   {
827       if (0 == memcmp (peer, &cur->id, sizeof (cur->id)))
828         break; /* already suggesting */
829       cur = cur->next;
830   }
831   if (NULL == cur)
832   {
833       cur = GNUNET_malloc (sizeof (struct GAS_Addresses_Suggestion_Requests));
834       cur->id = (*peer);
835       GNUNET_CONTAINER_DLL_insert (handle->r_head, handle->r_tail, cur);
836   }
837
838   /* Get prefered address from solver */
839   aa = (struct ATS_Address *) handle->s_get (handle->solver, handle->addresses, peer);
840   if (NULL == aa)
841   {
842     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
843                 "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
844     return;
845   }
846
847   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
848               "Suggesting address %p for peer `%s'\n", aa, GNUNET_i2s (peer));
849
850   ats_count = assemble_ats_information (aa, &ats);
851   GAS_scheduling_transmit_address_suggestion (peer,
852                                               aa->plugin,
853                                               aa->addr, aa->addr_len,
854                                               aa->session_id,
855                                               ats, ats_count,
856                                               aa->assigned_bw_out,
857                                               aa->assigned_bw_in);
858
859   aa->block_interval = GNUNET_TIME_relative_add (aa->block_interval, ATS_BLOCKING_DELTA);
860   aa->blocked_until = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), aa->block_interval);
861
862   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
863        "Address %p ready for suggestion, block interval now %llu \n",
864        aa, aa->block_interval);
865
866   GNUNET_free (ats);
867 }
868
869
870 static int
871 reset_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
872 {
873   struct ATS_Address *aa = value;
874
875   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
876               "Resetting interval for peer `%s' address %p from %llu to 0\n",
877               GNUNET_i2s (&aa->peer), aa, aa->block_interval);
878
879   aa->blocked_until = GNUNET_TIME_UNIT_ZERO_ABS;
880   aa->block_interval = GNUNET_TIME_UNIT_ZERO;
881   return GNUNET_OK;
882 }
883
884
885 void
886 GAS_addresses_handle_backoff_reset (const struct GNUNET_PeerIdentity *peer)
887 {
888   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
889               "Received `%s' for peer `%s'\n",
890               "RESET BACKOFF",
891               GNUNET_i2s (peer));
892
893   GNUNET_break (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses,
894                                               &peer->hashPubKey,
895                                               &reset_address_it,
896                                               NULL));
897 }
898
899
900 void
901 GAS_addresses_change_preference (const struct GNUNET_PeerIdentity *peer,
902                                  enum GNUNET_ATS_PreferenceKind kind,
903                                  float score)
904 {
905   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
906               "Received `%s' for peer `%s'\n",
907               "CHANGE PREFERENCE",
908               GNUNET_i2s (peer));
909
910   if (GNUNET_NO == handle->running)
911     return;
912
913   /* Tell solver about update */
914   handle->s_pref (handle->solver, peer, kind, score);
915 }
916
917 static unsigned int
918 load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned long long *out_dest, unsigned long long *in_dest, int dest_length)
919 {
920   int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
921   char * entry_in = NULL;
922   char * entry_out = NULL;
923   char * quota_out_str;
924   char * quota_in_str;
925   int c;
926
927   for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
928   {
929     in_dest[c] = 0;
930     out_dest[c] = 0;
931     switch (quotas[c]) {
932       case GNUNET_ATS_NET_UNSPECIFIED:
933         entry_out = "UNSPECIFIED_QUOTA_OUT";
934         entry_in = "UNSPECIFIED_QUOTA_IN";
935         break;
936       case GNUNET_ATS_NET_LOOPBACK:
937         entry_out = "LOOPBACK_QUOTA_OUT";
938         entry_in = "LOOPBACK_QUOTA_IN";
939         break;
940       case GNUNET_ATS_NET_LAN:
941         entry_out = "LAN_QUOTA_OUT";
942         entry_in = "LAN_QUOTA_IN";
943         break;
944       case GNUNET_ATS_NET_WAN:
945         entry_out = "WAN_QUOTA_OUT";
946         entry_in = "WAN_QUOTA_IN";
947         break;
948       case GNUNET_ATS_NET_WLAN:
949         entry_out = "WLAN_QUOTA_OUT";
950         entry_in = "WLAN_QUOTA_IN";
951         break;
952       default:
953         break;
954     }
955
956     if ((entry_in == NULL) || (entry_out == NULL))
957       continue;
958
959     /* quota out */
960     if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_out, &quota_out_str))
961     {
962       if (0 == strcmp(quota_out_str, BIG_M_STRING) ||
963           (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str, &out_dest[c])))
964         out_dest[c] = UINT32_MAX;
965
966       GNUNET_free (quota_out_str);
967       quota_out_str = NULL;
968     }
969     else if (GNUNET_ATS_NET_UNSPECIFIED == quotas[c])
970       out_dest[c] = UINT32_MAX;
971     else
972       out_dest[c] = UINT32_MAX;
973
974     /* quota in */
975     if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_in, &quota_in_str))
976     {
977       if (0 == strcmp(quota_in_str, BIG_M_STRING) ||
978           (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &in_dest[c])))
979         in_dest[c] = UINT32_MAX;
980
981       GNUNET_free (quota_in_str);
982       quota_in_str = NULL;
983     }
984     else if (GNUNET_ATS_NET_UNSPECIFIED == quotas[c])
985     {
986       in_dest[c] = UINT32_MAX;
987     }
988     else
989     {
990         in_dest[c] = UINT32_MAX;
991     }
992     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded quota: %s %u, %s %u\n", entry_in, in_dest[c], entry_out, out_dest[c]);
993
994   }
995   return GNUNET_ATS_NetworkTypeCount;
996 }
997
998
999 static void
1000 bandwidth_changed_cb (struct ATS_Address *address)
1001 {
1002   struct GAS_Addresses_Suggestion_Requests *cur;
1003   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bandwidth assignment changed for peer %s \n", GNUNET_i2s(&address->peer));
1004   struct GNUNET_ATS_Information *ats;
1005   unsigned int ats_count;
1006
1007   cur = handle->r_head;
1008   while (NULL != cur)
1009   {
1010       if (0 == memcmp (&address->peer, &cur->id, sizeof (cur->id)))
1011         break; /* we have an address request pending*/
1012       cur = cur->next;
1013   }
1014   if (NULL == cur)
1015   {
1016       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1017                   "Nobody is interested in peer `%s' :(\n",GNUNET_i2s (&address->peer));
1018       return;
1019   }
1020
1021   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1022               "Sending bandwidth update for peer `%s'\n",GNUNET_i2s (&address->peer));
1023
1024   ats_count = assemble_ats_information (address, &ats);
1025   GAS_scheduling_transmit_address_suggestion (&address->peer,
1026                                               address->plugin,
1027                                               address->addr, address->addr_len,
1028                                               address->session_id,
1029                                               ats, ats_count,
1030                                               address->assigned_bw_out,
1031                                               address->assigned_bw_in);
1032   GNUNET_free (ats);
1033 }
1034
1035
1036 /**
1037  * Initialize address subsystem.
1038  *
1039  * @param cfg configuration to use
1040  * @param stats the statistics handle to use
1041  */
1042 struct GAS_Addresses_Handle *
1043 GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
1044                     const struct GNUNET_STATISTICS_Handle *stats)
1045 {
1046   struct GAS_Addresses_Handle *ah;
1047   int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
1048   unsigned long long  quotas_in[GNUNET_ATS_NetworkTypeCount];
1049   unsigned long long  quotas_out[GNUNET_ATS_NetworkTypeCount];
1050   int quota_count;
1051   char *mode_str;
1052   int c;
1053
1054   ah = GNUNET_malloc (sizeof (struct GAS_Addresses_Handle));
1055   handle = ah;
1056   handle->running = GNUNET_NO;
1057
1058   /* Initialize the addresses database */
1059   ah->addresses = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO);
1060   GNUNET_assert (NULL != ah->addresses);
1061
1062   /* Figure out configured solution method */
1063   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", "MODE", &mode_str))
1064   {
1065       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "No ressource assignment method configured, using simplistic approch\n");
1066       ah->ats_mode = MODE_SIMPLISTIC;
1067   }
1068   else
1069   {
1070       for (c = 0; c < strlen (mode_str); c++)
1071         mode_str[c] = toupper (mode_str[c]);
1072       if (0 == strcmp (mode_str, "SIMPLISTIC"))
1073       {
1074           ah->ats_mode = MODE_SIMPLISTIC;
1075       }
1076       else if (0 == strcmp (mode_str, "MLP"))
1077       {
1078           ah->ats_mode = MODE_MLP;
1079 #if !HAVE_LIBGLPK
1080           GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Assignment method `%s' configured, but GLPK is not availabe, please install \n", mode_str);
1081           ah->ats_mode = MODE_SIMPLISTIC;
1082 #endif
1083       }
1084       else
1085       {
1086           GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid ressource assignment method `%s' configured, using simplistic approch\n", mode_str);
1087           ah->ats_mode = MODE_SIMPLISTIC;
1088       }
1089       GNUNET_free (mode_str);
1090   }
1091   /* Start configured solution method */
1092   switch (ah->ats_mode)
1093   {
1094     case MODE_MLP:
1095       /* Init the MLP solver with default values */
1096 #if HAVE_LIBGLPK
1097       ah->ats_mode = MODE_MLP;
1098       ah->s_init = &GAS_mlp_init;
1099       ah->s_add = &GAS_mlp_address_add;
1100       ah->s_update = &GAS_mlp_address_update;
1101       ah->s_get = &GAS_mlp_get_preferred_address;
1102       ah->s_pref = &GAS_mlp_address_change_preference;
1103       ah->s_del =  &GAS_mlp_address_delete;
1104       ah->s_done = &GAS_mlp_done;
1105 #else
1106       GNUNET_free (ah);
1107       return NULL;
1108 #endif
1109       break;
1110     case MODE_SIMPLISTIC:
1111       /* Init the simplistic solver with default values */
1112       ah->ats_mode = MODE_SIMPLISTIC;
1113       ah->s_init = &GAS_simplistic_init;
1114       ah->s_add = &GAS_simplistic_address_add;
1115       ah->s_update = &GAS_simplistic_address_update;
1116       ah->s_get = &GAS_simplistic_get_preferred_address;
1117       ah->s_pref = &GAS_simplistic_address_change_preference;
1118       ah->s_del  = &GAS_simplistic_address_delete;
1119       ah->s_done = &GAS_simplistic_done;
1120       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS started in %s mode\n", "SIMPLISTIC");
1121       break;
1122     default:
1123       return NULL;
1124       break;
1125   }
1126
1127   GNUNET_assert (NULL != ah->s_init);
1128   GNUNET_assert (NULL != ah->s_add);
1129   GNUNET_assert (NULL != ah->s_update);
1130   GNUNET_assert (NULL != ah->s_get);
1131   GNUNET_assert (NULL != ah->s_pref);
1132   GNUNET_assert (NULL != ah->s_del);
1133   GNUNET_assert (NULL != ah->s_done);
1134
1135   quota_count = load_quotas(cfg, quotas_in, quotas_out, GNUNET_ATS_NetworkTypeCount);
1136
1137   ah->solver = ah->s_init (cfg, stats, quotas, quotas_in, quotas_out, quota_count, &bandwidth_changed_cb);
1138   if (NULL == ah->solver)
1139   {
1140     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to initialize solver!\n");
1141     GNUNET_free (ah);
1142     return NULL;
1143   }
1144
1145   /* up and running */
1146   ah->running = GNUNET_YES;
1147   return ah;
1148 }
1149
1150
1151 /**
1152  * Free memory of address.
1153  *
1154  * @param cls NULL
1155  * @param key peer identity (unused)
1156  * @param value the 'struct ATS_Address' to free
1157  * @return GNUNET_OK (continue to iterate)
1158  */
1159 static int
1160 free_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
1161 {
1162   struct GAS_Addresses_Handle *handle = cls;
1163   struct ATS_Address *aa = value;
1164   handle->s_del (handle->solver, handle->addresses, aa, GNUNET_NO);
1165   destroy_address (aa);
1166   return GNUNET_OK;
1167 }
1168
1169
1170 void
1171 GAS_addresses_destroy_all (struct GAS_Addresses_Handle *handle)
1172 {
1173   if (GNUNET_NO == handle->running)
1174     return;
1175
1176   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1177               "Received `%s'\n",
1178               "DESTROY ALL");
1179
1180   if (handle->addresses != NULL)
1181     GNUNET_CONTAINER_multihashmap_iterate (handle->addresses, &free_address_it, handle);
1182 }
1183
1184
1185 /**
1186  * Shutdown address subsystem.
1187  */
1188 void
1189 GAS_addresses_done (struct GAS_Addresses_Handle *handle)
1190 {
1191   struct GAS_Addresses_Suggestion_Requests *cur;
1192
1193   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1194               "Shutting down addresses\n");
1195   GNUNET_assert (NULL != handle);
1196   GAS_addresses_destroy_all (handle);
1197   handle->running = GNUNET_NO;
1198   GNUNET_CONTAINER_multihashmap_destroy (handle->addresses);
1199   handle->addresses = NULL;
1200   while (NULL != (cur = handle->r_head))
1201   {
1202       GNUNET_CONTAINER_DLL_remove (handle->r_head, handle->r_tail, cur);
1203       GNUNET_free (cur);
1204   }
1205   handle->s_done (handle->solver);
1206   GNUNET_free (handle);
1207   /* Stop configured solution method */
1208
1209 }
1210
1211 struct PeerIteratorContext
1212 {
1213   GNUNET_ATS_Peer_Iterator it;
1214   void *it_cls;
1215   struct GNUNET_CONTAINER_MultiHashMap *peers_returned;
1216 };
1217
1218 static int
1219 peer_it (void *cls,
1220          const struct GNUNET_HashCode * key,
1221          void *value)
1222 {
1223   struct PeerIteratorContext *ip_ctx = cls;
1224   struct GNUNET_PeerIdentity tmp;
1225
1226   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(ip_ctx->peers_returned, key))
1227   {
1228       GNUNET_CONTAINER_multihashmap_put(ip_ctx->peers_returned, key, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1229       tmp.hashPubKey = (*key);
1230       ip_ctx->it (ip_ctx->it_cls, &tmp);
1231   }
1232
1233   return GNUNET_OK;
1234 }
1235
1236 /**
1237  * Return all peers currently known to ATS
1238  *
1239  * @param p_it the iterator to call for every peer, callbach with id == NULL
1240  *        when done
1241  * @param p_it_cls the closure for the iterator
1242  */
1243 void
1244 GAS_addresses_iterate_peers (GNUNET_ATS_Peer_Iterator p_it, void *p_it_cls)
1245 {
1246   struct PeerIteratorContext ip_ctx;
1247   unsigned int size;
1248
1249   if (NULL == p_it)
1250       return;
1251   GNUNET_assert (NULL != handle->addresses);
1252
1253   size = GNUNET_CONTAINER_multihashmap_size(handle->addresses);
1254   if (0 != size)
1255   {
1256     ip_ctx.it = p_it;
1257     ip_ctx.it_cls = p_it_cls;
1258     ip_ctx.peers_returned = GNUNET_CONTAINER_multihashmap_create (size, GNUNET_NO);
1259     GNUNET_CONTAINER_multihashmap_iterate (handle->addresses, &peer_it, &ip_ctx);
1260     GNUNET_CONTAINER_multihashmap_destroy (ip_ctx.peers_returned);
1261   }
1262   p_it (p_it_cls, NULL);
1263 }
1264
1265 struct PeerInfoIteratorContext
1266 {
1267   GNUNET_ATS_PeerInfo_Iterator it;
1268   void *it_cls;
1269 };
1270
1271
1272 static int 
1273 peerinfo_it (void *cls,
1274              const struct GNUNET_HashCode * key,
1275              void *value)
1276 {
1277   struct PeerInfoIteratorContext *pi_ctx = cls;
1278   struct ATS_Address *addr = (struct ATS_Address *)  value;
1279   struct GNUNET_ATS_Information *ats;
1280   uint32_t ats_count;
1281
1282   if (NULL != pi_ctx->it)
1283   {
1284     ats_count = assemble_ats_information (addr, &ats);
1285
1286     pi_ctx->it (pi_ctx->it_cls,
1287                 &addr->peer,
1288                 addr->plugin,
1289                 addr->addr, addr->addr_len,
1290                 addr->active,
1291                 ats, ats_count,
1292                 addr->assigned_bw_out,
1293                 addr->assigned_bw_in);
1294     GNUNET_free (ats);
1295   }
1296   return GNUNET_YES;
1297 }
1298
1299
1300 /**
1301  * Return all peers currently known to ATS
1302  *
1303  * @param peer the respective peer
1304  * @param pi_it the iterator to call for every peer
1305  * @param pi_it_cls the closure for the iterator
1306  */
1307 void
1308 GAS_addresses_get_peer_info (const struct GNUNET_PeerIdentity *peer, GNUNET_ATS_PeerInfo_Iterator pi_it, void *pi_it_cls)
1309 {
1310   struct PeerInfoIteratorContext pi_ctx;
1311   struct GNUNET_BANDWIDTH_Value32NBO zero_bw;
1312   GNUNET_assert (NULL != peer);
1313   GNUNET_assert (NULL != handle->addresses);
1314   if (NULL == pi_it)
1315     return; /* does not make sense without callback */
1316
1317   zero_bw = GNUNET_BANDWIDTH_value_init (0);
1318   pi_ctx.it = pi_it;
1319   pi_ctx.it_cls = pi_it_cls;
1320
1321   GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses, &peer->hashPubKey, &peerinfo_it, &pi_ctx);
1322
1323   if (NULL != pi_it)
1324     pi_it (pi_it_cls, NULL, NULL, NULL, 0, GNUNET_NO, NULL, 0, zero_bw, zero_bw);
1325
1326 }
1327
1328
1329 /* end of gnunet-service-ats_addresses.c */