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