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