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