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