big ATS refactoring, no serious semantic changes should stem from this
[oweals/gnunet.git] / src / ats / gnunet-service-ats_plugins.c
1 /*
2  This file is part of GNUnet.
3  (C) 2011-2014 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_plugins.c
23  * @brief ats service plugin management
24  * @author Matthias Wachs
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_ats_service.h"
30 #include "gnunet-service-ats.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet_ats_plugin.h"
33 #include "gnunet-service-ats_addresses.h"
34 #include "gnunet-service-ats_performance.h"
35 #include "gnunet-service-ats_plugins.h"
36 #include "gnunet-service-ats_scheduling.h"
37 #include "gnunet-service-ats_normalization.h"
38 #include "ats.h"
39
40
41
42 /**
43  * Configured ATS solver
44  */
45 static int ats_mode;
46
47 /**
48  * Solver handle. FIXME: TYPE!?
49  */
50 static void *solver;
51
52 /**
53  * Solver functions. FIXME.
54  */
55 static struct GNUNET_ATS_PluginEnvironment env;
56
57 /**
58  * Solver plugin name as string
59  */
60 static char *plugin;
61
62
63 /**
64  * The preference changed for a peer, update solver.
65  *
66  * @param peer the peer
67  * @param kind the ATS kind
68  * @param pref_rel the new relative preference value
69  */
70 void
71 GAS_normalized_preference_changed (const struct GNUNET_PeerIdentity *peer,
72                                    enum GNUNET_ATS_PreferenceKind kind,
73                                    double pref_rel)
74 {
75   /* Tell solver about update */
76   env.sf.s_pref (solver, peer, kind, pref_rel);
77 }
78
79
80 /**
81  * The relative value for a property changed
82  *
83  * @param address the peer
84  * @param type the ATS type
85  * @param prop_rel the new relative preference value
86  */
87 void
88 GAS_normalized_property_changed (struct ATS_Address *address,
89                                  uint32_t type,
90                                  double prop_rel)
91 {
92   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
93               "Normalized property %s for peer `%s' changed to %.3f \n",
94               GNUNET_ATS_print_property_type (type),
95               GNUNET_i2s (&address->peer),
96               prop_rel);
97   env.sf.s_address_update_property (solver,
98                                     address,
99                                     type,
100                                     0,
101                                     prop_rel);
102 }
103
104
105 /**
106  * Solver information callback
107  *
108  * @param cls the closure
109  * @param op the operation
110  * @param status operation status
111  * @param add additional information
112  */
113 static void
114 solver_info_cb (void *cls,
115                 enum GAS_Solver_Operation op,
116                 enum GAS_Solver_Status status,
117                 enum GAS_Solver_Additional_Information add)
118 {
119   char *add_info;
120
121   switch (add) {
122     case GAS_INFO_NONE:
123       add_info = "GAS_INFO_NONE";
124       break;
125     case GAS_INFO_FULL:
126       add_info = "GAS_INFO_MLP_FULL";
127       break;
128     case GAS_INFO_UPDATED:
129       add_info = "GAS_INFO_MLP_UPDATED";
130       break;
131     case GAS_INFO_PROP_ALL:
132       add_info = "GAS_INFO_PROP_ALL";
133       break;
134     case GAS_INFO_PROP_SINGLE:
135       add_info = "GAS_INFO_PROP_SINGLE";
136       break;
137     default:
138       add_info = "INVALID";
139       break;
140   }
141   switch (op)
142   {
143     case GAS_OP_SOLVE_START:
144       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
145           "Solver notifies `%s' with result `%s' `%s'\n", "GAS_OP_SOLVE_START",
146           (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL", add_info);
147       return;
148     case GAS_OP_SOLVE_STOP:
149       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
150           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_STOP",
151           (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL", add_info);
152       return;
153
154     case GAS_OP_SOLVE_SETUP_START:
155       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
156           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_START",
157           (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
158       return;
159
160     case GAS_OP_SOLVE_SETUP_STOP:
161       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
162           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_STOP",
163           (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
164       return;
165
166     case GAS_OP_SOLVE_MLP_LP_START:
167       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
168           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_START",
169           (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
170       return;
171     case GAS_OP_SOLVE_MLP_LP_STOP:
172       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
173           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_STOP",
174           (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
175       return;
176
177     case GAS_OP_SOLVE_MLP_MLP_START:
178       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
179           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_START",
180           (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
181       return;
182     case GAS_OP_SOLVE_MLP_MLP_STOP:
183       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
184           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_STOP",
185           (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
186       return;
187     case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
188       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
189           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
190           (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
191       return;
192     case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
193       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
194           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
195           (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
196       return;
197     default:
198       break;
199     }
200 }
201
202
203 /**
204  * Callback for solver to notify about assignment changes
205  *
206  * @param cls NULL
207  * @param address the address with changes
208  */
209 static void
210 bandwidth_changed_cb (void *cls, 
211                       struct ATS_Address *address)
212 {
213   uint32_t diff_out;
214   uint32_t diff_in;
215
216   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
217               "Bandwidth assignment changed for peer %s \n",
218               GNUNET_i2s (&address->peer));
219
220   /* Notify performance clients about changes to address */
221   GAS_performance_notify_all_clients (&address->peer,
222                                       address->plugin,
223                                       address->addr,
224                                       address->addr_len,
225                                       address->active, 
226                                       address->atsi,
227                                       address->atsi_count,
228                                       GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
229                                       GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
230
231   if ( (0 == address->assigned_bw_in) &&
232        (0 == address->assigned_bw_out) )
233   {
234     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
235                "Telling transport to disconnect peer `%s'\n",
236                 GNUNET_i2s (&address->peer));
237
238     /* Notify scheduling clients about suggestion */
239     GAS_scheduling_transmit_address_suggestion (&address->peer,
240                                                 address->session_id,
241                                                 GNUNET_BANDWIDTH_ZERO,
242                                                 GNUNET_BANDWIDTH_ZERO);
243     return;
244   }
245
246   /* Do bandwidth stability check */
247   diff_out = abs (address->assigned_bw_out - address->last_notified_bw_out);
248   diff_in = abs (address->assigned_bw_in - address->last_notified_bw_in);
249
250   if ( (diff_out < htonl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) &&
251        (diff_in < htonl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) )
252     return;
253
254   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
255       "Sending bandwidth update for peer `%s': %u %u\n",
256       GNUNET_i2s (&address->peer), address->assigned_bw_out,
257       address->assigned_bw_out);
258
259   /* *Notify scheduling clients about suggestion */
260   GAS_scheduling_transmit_address_suggestion (&address->peer,
261                                               address->session_id,
262                                               GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
263                                               GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
264
265   address->last_notified_bw_out = address->assigned_bw_out;
266   address->last_notified_bw_in = address->assigned_bw_in;
267 }
268
269
270 /**
271  * Load quotas for networks from configuration
272  *
273  * @param cfg configuration handle
274  * @param out_dest where to write outbound quotas
275  * @param in_dest where to write inbound quotas
276  * @param dest_length length of inbound and outbound arrays
277  * @return number of networks loaded
278  */
279 static unsigned int
280 load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
281     unsigned long long *out_dest, unsigned long long *in_dest, int dest_length)
282 {
283   char * entry_in = NULL;
284   char * entry_out = NULL;
285   char * quota_out_str;
286   char * quota_in_str;
287   int c;
288   int res;
289
290   for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
291   {
292     in_dest[c] = 0;
293     out_dest[c] = 0;
294     GNUNET_asprintf (&entry_out,
295                      "%s_QUOTA_OUT",
296                      GNUNET_ATS_print_network_type (c));
297     GNUNET_asprintf (&entry_in,
298                      "%s_QUOTA_IN",
299                      GNUNET_ATS_print_network_type (c));
300
301     /* quota out */
302     if (GNUNET_OK
303         == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", entry_out,
304             &quota_out_str))
305     {
306       res = GNUNET_NO;
307       if (0 == strcmp (quota_out_str, GNUNET_ATS_MaxBandwidthString))
308       {
309         out_dest[c] = GNUNET_ATS_MaxBandwidth;
310         res = GNUNET_YES;
311       }
312       if ((GNUNET_NO == res)
313           && (GNUNET_OK
314               == GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str,
315                   &out_dest[c])))
316         res = GNUNET_YES;
317       if ((GNUNET_NO == res)
318           && (GNUNET_OK
319               == GNUNET_CONFIGURATION_get_value_number (cfg, "ats", entry_out,
320                   &out_dest[c])))
321         res = GNUNET_YES;
322
323       if (GNUNET_NO == res)
324       {
325         GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
326                    _("Could not load quota for network `%s':  `%s', assigning default bandwidth %llu\n"),
327                    GNUNET_ATS_print_network_type (c),
328                    quota_out_str,
329                    GNUNET_ATS_DefaultBandwidth);
330         out_dest[c] = GNUNET_ATS_DefaultBandwidth;
331       }
332       else
333       {
334         GNUNET_log(GNUNET_ERROR_TYPE_INFO,
335                    _("Outbound quota configure for network `%s' is %llu\n"),
336                    GNUNET_ATS_print_network_type (c),
337                    out_dest[c]);
338       }
339       GNUNET_free(quota_out_str);
340     }
341     else
342     {
343       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
344                  _("No outbound quota configured for network `%s', assigning default bandwidth %llu\n"),
345                  GNUNET_ATS_print_network_type (c),
346                  GNUNET_ATS_DefaultBandwidth);
347       out_dest[c] = GNUNET_ATS_DefaultBandwidth;
348     }
349
350     /* quota in */
351     if (GNUNET_OK
352         == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", entry_in,
353             &quota_in_str))
354     {
355       res = GNUNET_NO;
356       if (0 == strcmp (quota_in_str, GNUNET_ATS_MaxBandwidthString))
357       {
358         in_dest[c] = GNUNET_ATS_MaxBandwidth;
359         res = GNUNET_YES;
360       }
361       if ((GNUNET_NO == res)
362           && (GNUNET_OK
363               == GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &in_dest[c])))
364         res = GNUNET_YES;
365       if ((GNUNET_NO == res)
366           && (GNUNET_OK
367               == GNUNET_CONFIGURATION_get_value_number (cfg, "ats", entry_in,
368                   &in_dest[c])))
369         res = GNUNET_YES;
370
371       if (GNUNET_NO == res)
372       {
373         GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
374                    _("Could not load quota for network `%s':  `%s', assigning default bandwidth %llu\n"),
375                    GNUNET_ATS_print_network_type (c),
376                    quota_in_str,
377                    GNUNET_ATS_DefaultBandwidth);
378         in_dest[c] = GNUNET_ATS_DefaultBandwidth;
379       }
380       else
381       {
382         GNUNET_log(GNUNET_ERROR_TYPE_INFO,
383                    _("Inbound quota configured for network `%s' is %llu\n"),
384                    GNUNET_ATS_print_network_type (c),
385                    in_dest[c]);
386       }
387       GNUNET_free(quota_in_str);
388     }
389     else
390     {
391       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
392                  _("No outbound quota configure for network `%s', assigning default bandwidth %llu\n"),
393                  GNUNET_ATS_print_network_type (c),
394                  GNUNET_ATS_DefaultBandwidth);
395       in_dest[c] = GNUNET_ATS_DefaultBandwidth;
396     }
397     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
398                "Loaded quota for network `%s' (in/out): %llu %llu\n",
399                GNUNET_ATS_print_network_type (c),
400                in_dest[c],
401                out_dest[c]);
402     GNUNET_free(entry_out);
403     GNUNET_free(entry_in);
404   }
405   return GNUNET_ATS_NetworkTypeCount;
406 }
407
408
409 /**
410  * Initialize plugins subsystem.
411  *
412  * @param cfg configuration to use
413  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (failed to load
414  *         solver plugin)
415  */
416 int
417 GAS_plugins_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
418 {
419   unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
420   unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
421   char *mode_str;
422   char *plugin_short;
423   int c;
424
425   /* Figure out configured solution method */
426   if (GNUNET_SYSERR ==
427       GNUNET_CONFIGURATION_get_value_string (cfg, "ats", "MODE", &mode_str))
428   {
429     GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
430                "No resource assignment method configured, using proportional approach\n");
431     ats_mode = MODE_PROPORTIONAL;
432   }
433   else
434   {
435     for (c = 0; c < strlen (mode_str); c++)
436       mode_str[c] = toupper (mode_str[c]);
437     if (0 == strcmp (mode_str, "PROPORTIONAL"))
438       ats_mode = MODE_PROPORTIONAL;
439     else if (0 == strcmp (mode_str, "MLP"))
440     {
441       ats_mode = MODE_MLP;
442 #if !HAVE_LIBGLPK
443       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
444                  "Assignment method `%s' configured, but GLPK is not available, please install \n",
445                  mode_str);
446       ats_mode = MODE_PROPORTIONAL;
447 #endif
448     }
449     else if (0 == strcmp (mode_str, "RIL"))
450       ats_mode = MODE_RIL;
451     else
452     {
453       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
454                  "Invalid resource assignment method `%s' configured, using proportional approach\n",
455                  mode_str);
456       ats_mode = MODE_PROPORTIONAL;
457     }
458     GNUNET_free(mode_str);
459   }
460
461   load_quotas (cfg, quotas_out, quotas_in, GNUNET_ATS_NetworkTypeCount);
462   env.info_cb = &solver_info_cb;
463   env.info_cb_cls = NULL;
464   env.bandwidth_changed_cb = &bandwidth_changed_cb;
465   env.bw_changed_cb_cls = NULL;
466   env.get_preferences = &GAS_normalization_get_preferences_by_peer;
467   env.get_preference_cls = NULL;
468   env.get_property = &GAS_normalization_get_properties;
469   env.get_property_cls = NULL;
470   env.cfg = cfg;
471   env.stats = GSA_stats;
472   env.addresses = GSA_addresses;
473
474   env.network_count = GNUNET_ATS_NetworkTypeCount;
475   int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
476   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
477   {
478     env.networks[c] = networks[c];
479     env.out_quota[c] = quotas_out[c];
480     env.in_quota[c] = quotas_in[c];
481   }
482
483   switch (ats_mode) {
484     case MODE_PROPORTIONAL:
485       plugin_short = "proportional";
486       break;
487     case MODE_MLP:
488       plugin_short = "mlp";
489       break;
490     case MODE_RIL:
491       plugin_short = "ril";
492       break;
493     default:
494       plugin_short = NULL;
495       break;
496   }
497   GNUNET_asprintf (&plugin,
498                    "libgnunet_plugin_ats_%s",
499                    plugin_short);
500   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
501               "Initializing solver `%s '`%s'\n",
502               plugin_short,
503               plugin);
504   if (NULL == (solver = GNUNET_PLUGIN_load (plugin, &env)))
505   {
506     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
507                 _("Failed to initialize solver `%s'!\n"),
508                 plugin);
509     return GNUNET_SYSERR;
510   }
511
512
513   GNUNET_assert (NULL != env.sf.s_add);
514   GNUNET_assert (NULL != env.sf.s_address_update_property);
515   GNUNET_assert (NULL != env.sf.s_get);
516   GNUNET_assert (NULL != env.sf.s_get_stop);
517   GNUNET_assert (NULL != env.sf.s_pref);
518   GNUNET_assert (NULL != env.sf.s_feedback);
519   GNUNET_assert (NULL != env.sf.s_del);
520   GNUNET_assert (NULL != env.sf.s_bulk_start);
521   GNUNET_assert (NULL != env.sf.s_bulk_stop);
522
523   if (NULL == solver)
524   {
525     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
526                 _("Failed to initialize solver!\n"));
527     return GNUNET_SYSERR;
528   }
529   return GNUNET_OK;
530 }
531
532
533 /**
534  * Shutdown address subsystem.
535  */
536 void
537 GAS_plugins_done ()
538 {
539   GNUNET_PLUGIN_unload (plugin,
540                         solver);
541   solver = NULL;
542   GNUNET_free (plugin);
543   plugin = NULL;
544 }
545
546
547 void
548 GAS_plugin_new_address (struct ATS_Address *new_address,
549                         enum GNUNET_ATS_Network_Type addr_net,
550                         const struct GNUNET_ATS_Information *atsi,
551                         uint32_t atsi_count)
552 {
553   env.sf.s_add (solver, new_address, addr_net);
554   env.sf.s_bulk_start (solver);
555   GAS_normalization_normalize_property (new_address,
556                                         atsi,
557                                         atsi_count);
558   env.sf.s_bulk_stop (solver);
559 }
560
561
562 void
563 GAS_plugin_update_address (struct ATS_Address *address,
564                            const struct GNUNET_ATS_Information *atsi,
565                            uint32_t atsi_count)
566 {
567   env.sf.s_bulk_start (solver);
568   GAS_normalization_normalize_property (address,
569                                         atsi,
570                                         atsi_count);
571   env.sf.s_bulk_stop (solver);
572 }
573
574
575 void
576 GAS_plugin_delete_address (struct ATS_Address *address)
577 {
578   env.sf.s_del (solver, address, GNUNET_NO);
579 }
580
581
582 void
583 GAS_plugin_update_preferences (void *client,
584                                const struct GNUNET_PeerIdentity *peer,
585                                enum GNUNET_ATS_PreferenceKind kind,
586                                float score_abs)
587 {
588   env.sf.s_bulk_start (solver);
589   /* Tell normalization about change, normalization will call callback if preference changed */
590   GAS_normalization_normalize_preference (client, peer, kind, score_abs);
591   env.sf.s_bulk_stop (solver);
592 }
593
594
595 void
596 GAS_plugin_preference_feedback (void *application,
597                                 const struct GNUNET_PeerIdentity *peer,
598                                 const struct GNUNET_TIME_Relative scope,
599                                 enum GNUNET_ATS_PreferenceKind kind,
600                                 float score_abs)
601 {
602   env.sf.s_feedback (solver,
603                      application,
604                      peer, 
605                      scope, 
606                      kind,
607                      score_abs);
608 }
609
610
611 void
612 GAS_plugin_solver_lock ()
613 {
614   env.sf.s_bulk_start (solver);
615 }
616
617
618 void
619 GAS_plugin_solver_unlock ()
620 {
621   env.sf.s_bulk_start (solver);
622 }
623
624
625 void
626 GAS_plugin_request_connect_start (const struct GNUNET_PeerIdentity *pid)
627 {
628   const struct ATS_Address *aa;
629
630   aa = env.sf.s_get (solver, pid);
631   if (NULL == aa)
632   {
633     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
634                 "Cannot suggest address for peer `%s'\n",
635                 GNUNET_i2s (pid));
636     return;
637   }
638   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
639              "Suggesting address %p for peer `%s'\n",
640              aa, 
641              GNUNET_i2s (pid));
642
643   GAS_scheduling_transmit_address_suggestion (pid,
644                                               aa->session_id,
645                                               GNUNET_BANDWIDTH_value_init (aa->assigned_bw_out),
646                                               GNUNET_BANDWIDTH_value_init (aa->assigned_bw_in));
647
648   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
649              "Address %p ready for suggestion\n",
650              aa);
651 }
652
653
654 void
655 GAS_plugin_request_connect_stop (const struct GNUNET_PeerIdentity *pid)
656 {
657   env.sf.s_get_stop (solver, pid);
658 }
659
660
661 /* end of gnunet-service-ats_plugins.c */