-removed obsolete functions
[oweals/gnunet.git] / src / ats-tool / gnunet-ats.c
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2009--2015 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., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * @file ats-tool/gnunet-ats.c
23  * @brief ATS command line tool
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_transport_service.h"
31
32 /**
33  * String to respresent unlimited
34  */
35 #define UNLIMITED_STRING "unlimited"
36
37
38 /**
39  * CLI Opt:
40  */
41 static int opt_resolve_addresses_numeric;
42
43 /**
44  * CLI Opt: Print verbose ATS information
45  */
46 static int opt_verbose;
47
48 /**
49  * CLI Option: List only addresses currently used (active)
50  */
51 static int opt_list_used;
52
53 /**
54  * CLI Option: List all addresses
55  */
56 static int opt_list_all;
57
58 /**
59  * CLI Option: set preference
60  */
61 static int opt_set_pref;
62
63 /**
64  * CLI Option: print quotas configured
65  */
66 static int opt_print_quotas;
67
68 /**
69  * CLI Option: Monitor addresses used
70  */
71 static int opt_monitor;
72
73 /**
74  * CLI Option: use specific peer
75  */
76 static char *opt_pid_str;
77
78 /**
79  * CLI Option: preference type to set
80  */
81 static char *opt_type_str;
82
83 /**
84   * CLI Option: preference value to set
85  */
86 static unsigned int opt_pref_value;
87
88 /**
89  * Final status code.
90  */
91 static int ret;
92
93 /**
94  * Number of results returned from service
95  */
96 static int stat_results;
97
98 /**
99  * State: all pending receive operations done?
100  */
101 static int stat_receive_done;
102
103 /**
104  * State: number of pending operations
105  */
106 static int stat_pending;
107
108 /**
109  * Which peer should we connect to?
110  */
111 static char *cpid_str;
112
113 /**
114  * ATS performance handle used
115  */
116 static struct GNUNET_ATS_PerformanceHandle *ph;
117
118 /**
119  * Our connectivity handle.
120  */
121 static struct GNUNET_ATS_ConnectivityHandle *ats_ch;
122
123 /**
124  * Handle for address suggestion request.
125  */
126 static struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh;
127
128 /**
129  * ATS address list handle used
130  */
131 static struct GNUNET_ATS_AddressListHandle *alh;
132
133 /**
134  * Configuration handle
135  */
136 static struct GNUNET_CONFIGURATION_Handle *cfg;
137
138 /**
139  * Shutdown task
140  */
141 static struct GNUNET_SCHEDULER_Task *shutdown_task;
142
143 /**
144  * Hashmap to store addresses
145  */
146 static struct GNUNET_CONTAINER_MultiPeerMap *addresses;
147
148
149 /**
150  * Structure used to remember all pending address resolutions.
151  * We keep address information in here while we talk to transport
152  * to map the address to a string.
153  */
154 struct PendingResolutions
155 {
156   /**
157    * Kept in a DLL.
158    */
159   struct PendingResolutions *next;
160
161   /**
162    * Kept in a DLL.
163    */
164   struct PendingResolutions *prev;
165
166   /**
167    * Copy of the address we are resolving.
168    */
169   struct GNUNET_HELLO_Address *address;
170
171   /**
172    * Handle to the transport request to convert the address
173    * to a string.
174    */
175   struct GNUNET_TRANSPORT_AddressToStringContext *tats_ctx;
176
177   /**
178    * Performance data.
179    */
180   struct GNUNET_ATS_Properties properties;
181
182   /**
183    * Amount of outbound bandwidth assigned by ATS.
184    */
185   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
186
187   /**
188    * Amount of inbound bandwidth assigned by ATS.
189    */
190   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
191
192   /**
193    * Is this an active address?
194    */
195   int active;
196 };
197
198
199 /**
200  * Information we keep for an address.  Used to avoid
201  * printing the same data multiple times.
202  */
203 struct ATSAddress
204 {
205   /**
206    * Address information.
207    */
208   struct GNUNET_HELLO_Address *address;
209
210   /**
211    * Current outbound bandwidth.
212    */
213   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
214
215   /**
216    * Current inbound bandwidth.
217    */
218   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
219
220   /**
221    * Is this an active address?
222    */
223   int active;
224
225 };
226
227
228 /**
229  * Head of list of pending resolution requests.
230  */
231 static struct PendingResolutions *head;
232
233 /**
234  * Tail of list of pending resolution requests.
235  */
236 static struct PendingResolutions *tail;
237
238
239 /**
240  * Free address corresponding to a given peer.
241  *
242  * @param cls NULL
243  * @param key peer identity
244  * @param value the `struct ATSAddress *` to be freed
245  * @return #GNUNET_YES (always)
246  */
247 static int
248 free_addr_it (void *cls,
249               const struct GNUNET_PeerIdentity *key,
250               void *value)
251 {
252   struct ATSAddress *a = value;
253
254   GNUNET_assert (GNUNET_OK ==
255                  GNUNET_CONTAINER_multipeermap_remove (addresses,
256                                                        key,
257                                                        value));
258   GNUNET_HELLO_address_free (a->address);
259   GNUNET_free (a);
260   return GNUNET_OK;
261 }
262
263
264 /**
265  * Task run on shutdown.
266  *
267  * @param cls NULL
268  * @param tc scheduler context
269  */
270 static void
271 end (void *cls,
272      const struct GNUNET_SCHEDULER_TaskContext *tc)
273 {
274   struct PendingResolutions * pr;
275   struct PendingResolutions * next;
276   unsigned int pending;
277
278   if (NULL != alh)
279   {
280     GNUNET_ATS_performance_list_addresses_cancel (alh);
281     alh = NULL;
282   }
283
284   if (NULL != ph)
285   {
286     GNUNET_ATS_performance_done (ph);
287     ph = NULL;
288   }
289
290   pending = 0;
291   next = head;
292   while (NULL != (pr = next))
293   {
294     next = pr->next;
295     GNUNET_CONTAINER_DLL_remove(head, tail, pr);
296     GNUNET_TRANSPORT_address_to_string_cancel (pr->tats_ctx);
297     GNUNET_free(pr->address);
298     GNUNET_free(pr);
299     pending++;
300   }
301   GNUNET_CONTAINER_multipeermap_iterate (addresses,
302                                          &free_addr_it,
303                                          NULL);
304   GNUNET_CONTAINER_multipeermap_destroy (addresses);
305   addresses = NULL;
306
307   if (0 < pending)
308     FPRINTF (stdout,
309              _("%u address resolutions had a timeout\n"),
310              pending);
311   if (opt_list_used || opt_list_all)
312     FPRINTF (stdout,
313              _("ATS returned stat_results for %u addresses\n"),
314              stat_results);
315
316   if (NULL != ats_sh)
317   {
318     GNUNET_ATS_connectivity_suggest_cancel (ats_sh);
319     ats_sh = NULL;
320   }
321   if (NULL != ats_ch)
322   {
323     GNUNET_ATS_connectivity_done (ats_ch);
324     ats_ch = NULL;
325   }
326   ret = 0;
327 }
328
329
330 /**
331  * Function to call with a textual representation of an address.  This
332  * function will be called several times with different possible
333  * textual representations, and a last time with @a address being NULL
334  * to signal the end of the iteration.  Note that @a address NULL
335  * always is the last call, regardless of the value in @a res.
336  *
337  * @param cls closure, a `struct PendingResolutions *`
338  * @param address NULL on end of iteration,
339  *        otherwise 0-terminated printable UTF-8 string,
340  *        in particular an empty string if @a res is #GNUNET_NO
341  * @param res result of the address to string conversion:
342  *        if #GNUNET_OK: conversion successful
343  *        if #GNUNET_NO: address was invalid (or not supported)
344  *        if #GNUNET_SYSERR: communication error (IPC error)
345  */
346 static void
347 transport_addr_to_str_cb (void *cls,
348                           const char *address,
349                           int res)
350 {
351   struct PendingResolutions *pr = cls;
352
353   if (NULL == address)
354   {
355     /* We're done */
356     GNUNET_CONTAINER_DLL_remove (head,
357                                  tail,
358                                  pr);
359     GNUNET_free (pr->address);
360     GNUNET_free (pr);
361     stat_pending--;
362
363     if ((GNUNET_YES == stat_receive_done) && (0 == stat_pending))
364     {
365       /* All messages received and no resolutions pending*/
366       if (shutdown_task != NULL)
367         GNUNET_SCHEDULER_cancel (shutdown_task);
368       shutdown_task = GNUNET_SCHEDULER_add_now (end, NULL);
369     }
370     return;
371   }
372   switch (res)
373   {
374   case GNUNET_SYSERR:
375     FPRINTF (stderr,
376              "Failed to convert address for peer `%s' plugin `%s' length %u to string (communication error)\n",
377              GNUNET_i2s (&pr->address->peer),
378              pr->address->transport_name,
379              (unsigned int) pr->address->address_length);
380     return;
381   case GNUNET_NO:
382     FPRINTF (stderr,
383              "Failed to convert address for peer `%s' plugin `%s' length %u to string (address invalid or not supported)\n",
384              GNUNET_i2s (&pr->address->peer),
385              pr->address->transport_name,
386              (unsigned int) pr->address->address_length);
387     return;
388   case GNUNET_OK:
389     /* continues below */
390     break;
391   default:
392     GNUNET_break (0);
393     return;
394   }
395
396   FPRINTF (stdout,
397            _("Peer `%s' plugin `%s', address `%s', `%s' bw out: %u Bytes/s, bw in %u Bytes/s, %s\n"),
398            GNUNET_i2s (&pr->address->peer),
399            pr->address->transport_name,
400            address,
401            GNUNET_ATS_print_network_type (pr->properties.scope),
402            ntohl (pr->bandwidth_out.value__),
403            ntohl (pr->bandwidth_in.value__),
404            pr->active ? _("active ") : _("inactive "));
405 }
406
407
408 /**
409  * Closure for #find_address_it().
410  */
411 struct AddressFindCtx
412 {
413   /**
414    * Address we are looking for.
415    */
416   const struct GNUNET_HELLO_Address *src;
417
418   /**
419    * Where to write the `struct ATSAddress` if we found one that matches.
420    */
421   struct ATSAddress *res;
422 };
423
424
425 /**
426  * Find address corresponding to a given peer.
427  *
428  * @param cls the `struct AddressFindCtx *`
429  * @param key peer identity
430  * @param value the `struct ATSAddress *` for an existing address
431  * @return #GNUNET_NO if we found a match, #GNUNET_YES if not
432  */
433 static int
434 find_address_it (void *cls,
435                  const struct GNUNET_PeerIdentity *key,
436                  void *value)
437 {
438   struct AddressFindCtx *actx = cls;
439   struct ATSAddress *exist = value;
440
441   if (0 == GNUNET_HELLO_address_cmp (actx->src, exist->address))
442   {
443     actx->res = exist;
444     return GNUNET_NO;
445   }
446   return GNUNET_YES;
447 }
448
449
450
451 /**
452  * Signature of a function that is called with QoS information about an address.
453  *
454  * @param cls closure (NULL)
455  * @param address the address, NULL if ATS service was disconnected
456  * @param active #GNUNET_YES if this address is actively used
457  *        to maintain a connection to a peer;
458  *        #GNUNET_NO if the address is not actively used;
459  *        #GNUNET_SYSERR if this address is no longer available for ATS
460  * @param bandwidth_out assigned outbound bandwidth for the connection
461  * @param bandwidth_in assigned inbound bandwidth for the connection
462  * @param prop performance data for the address (as far as known)
463  */
464 static void
465 ats_perf_mon_cb (void *cls,
466                  const struct GNUNET_HELLO_Address *address,
467                  int active,
468                  struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
469                  struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
470                  const struct GNUNET_ATS_Properties *prop)
471 {
472   struct PendingResolutions *pr;
473   struct PendingResolutions *cur;
474   struct PendingResolutions *next;
475
476   if (NULL == address)
477   {
478     /* ATS service temporarily disconnected, remove current state */
479     next = head;
480     for (cur = next; NULL != cur; cur = next)
481     {
482       next = cur->next;
483       GNUNET_CONTAINER_DLL_remove (head, tail, cur);
484       GNUNET_TRANSPORT_address_to_string_cancel (cur->tats_ctx);
485       GNUNET_HELLO_address_free (cur->address);
486       GNUNET_free (cur);
487     }
488     GNUNET_CONTAINER_multipeermap_iterate (addresses,
489                                            &free_addr_it,
490                                            NULL);
491     return;
492   }
493   if (GNUNET_SYSERR == active)
494   {
495     /* remove address */
496     struct AddressFindCtx actx;
497
498     actx.src = address;
499     actx.res = NULL;
500     GNUNET_CONTAINER_multipeermap_get_multiple (addresses,
501                                                 &address->peer,
502                                                 &find_address_it,
503                                                 &actx);
504     if (NULL == actx.res)
505     {
506       GNUNET_break (0);
507       return;
508     }
509     GNUNET_break(GNUNET_OK ==
510                  GNUNET_CONTAINER_multipeermap_remove (addresses,
511                                                        &address->peer,
512                                                        actx.res));
513     FPRINTF (stdout,
514              _("Removed address of peer `%s' with plugin `%s'\n"),
515              GNUNET_i2s (&address->peer),
516              actx.res->address->transport_name);
517     GNUNET_HELLO_address_free (actx.res);
518     return;
519   }
520
521   if (GNUNET_NO == opt_verbose)
522   {
523     struct AddressFindCtx actx;
524     struct ATSAddress *a;
525
526     actx.src = address;
527     actx.res = NULL;
528     GNUNET_CONTAINER_multipeermap_get_multiple (addresses,
529                                                 &address->peer,
530                                                 &find_address_it,
531                                                 &actx);
532     if ((NULL != actx.res))
533     {
534       if ((bandwidth_in.value__ == actx.res->bandwidth_in.value__) &&
535           (bandwidth_out.value__ == actx.res->bandwidth_out.value__) &&
536           (active == actx.res->active))
537       {
538         return; /* Nothing to do here */
539       }
540       else
541       {
542         actx.res->bandwidth_in = bandwidth_in;
543         actx.res->bandwidth_out = bandwidth_out;
544       }
545     }
546     else
547     {
548       a = GNUNET_new (struct ATSAddress);
549
550       a->address = GNUNET_HELLO_address_copy(address);
551       a->bandwidth_in = bandwidth_in;
552       a->bandwidth_out = bandwidth_out;
553       a->active = active;
554       GNUNET_CONTAINER_multipeermap_put (addresses,
555                                          &address->peer,
556                                          a,
557                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
558     }
559   }
560
561   pr = GNUNET_new (struct PendingResolutions);
562   pr->properties = *prop;
563   pr->address = GNUNET_HELLO_address_copy (address);
564   pr->bandwidth_in = bandwidth_in;
565   pr->bandwidth_out = bandwidth_out;
566   pr->active = active;
567   pr->tats_ctx = GNUNET_TRANSPORT_address_to_string (cfg, address,
568                                                      opt_resolve_addresses_numeric,
569                                                      GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
570                                                      &transport_addr_to_str_cb,
571                                                      pr);
572   GNUNET_CONTAINER_DLL_insert (head, tail, pr);
573   stat_results++;
574   stat_pending++;
575 }
576
577
578 /**
579  * Signature of a function that is called with QoS information about an address.
580  *
581  * @param cls closure (NULL)
582  * @param address the address, NULL if ATS service was disconnected
583  * @param active is this address actively used to maintain a connection
584           to a peer
585  * @param bandwidth_out assigned outbound bandwidth for the connection
586  * @param bandwidth_in assigned inbound bandwidth for the connection
587  * @param prop performance data for the address (as far as known)
588  */
589 static void
590 ats_perf_cb (void *cls,
591              const struct GNUNET_HELLO_Address *address,
592              int active,
593              struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
594              struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
595              const struct GNUNET_ATS_Properties *prop)
596 {
597   struct PendingResolutions *pr;
598
599   if (NULL == address)
600   {
601     /* All messages received */
602     stat_receive_done = GNUNET_YES;
603     alh = NULL;
604     if (0 == stat_pending)
605     {
606       /* All messages received and no resolutions pending*/
607       if (shutdown_task != NULL)
608         GNUNET_SCHEDULER_cancel (shutdown_task);
609       shutdown_task = GNUNET_SCHEDULER_add_now (end, NULL);
610     }
611     return;
612   }
613
614   pr = GNUNET_new (struct PendingResolutions);
615   pr->properties = *prop;
616   pr->address = GNUNET_HELLO_address_copy (address);
617   pr->bandwidth_in = bandwidth_in;
618   pr->bandwidth_out = bandwidth_out;
619   pr->active = active;
620   pr->tats_ctx = GNUNET_TRANSPORT_address_to_string (cfg, address,
621                                                      opt_resolve_addresses_numeric,
622                                                      GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
623                                                      &transport_addr_to_str_cb, pr);
624   GNUNET_CONTAINER_DLL_insert (head, tail, pr);
625   stat_results++;
626   stat_pending++;
627 }
628
629
630 /**
631  * Print information about the quotas configured for the various
632  * network scopes.
633  *
634  * @param cfg configuration to obtain quota information from
635  * @return total number of ATS network types known
636  */
637 static unsigned int
638 print_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg)
639 {
640   char * entry_in = NULL;
641   char * entry_out = NULL;
642   char * quota_out_str;
643   char * quota_in_str;
644   unsigned long long int quota_out;
645   unsigned long long int quota_in;
646   int c;
647
648   for (c = 0; (c < GNUNET_ATS_NetworkTypeCount); c++)
649   {
650
651     GNUNET_asprintf (&entry_out,
652                      "%s_QUOTA_OUT",
653                      GNUNET_ATS_print_network_type (c));
654     GNUNET_asprintf (&entry_in,
655                      "%s_QUOTA_IN",
656                      GNUNET_ATS_print_network_type (c));
657
658     /* quota out */
659     if (GNUNET_OK ==
660         GNUNET_CONFIGURATION_get_value_string (cfg,
661                                                "ats",
662                                                entry_out,
663                                                &quota_out_str))
664     {
665       if (0 == strcmp (quota_out_str, UNLIMITED_STRING)
666           || (GNUNET_SYSERR ==
667               GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str,
668                                                   &quota_out)))
669         quota_out = UINT32_MAX;
670
671       GNUNET_free(quota_out_str);
672       GNUNET_asprintf (&quota_out_str, "%llu", quota_out);
673     }
674     else
675     {
676       FPRINTF (stderr,
677                "Outbound quota for network `%11s' not configured!\n",
678                GNUNET_ATS_print_network_type (c));
679       GNUNET_asprintf (&quota_out_str, "-");
680     }
681     GNUNET_free (entry_out);
682
683     /* quota in */
684     if (GNUNET_OK ==
685         GNUNET_CONFIGURATION_get_value_string (cfg,
686                                                "ats",
687                                                entry_in,
688                                                &quota_in_str))
689     {
690       if (0 == strcmp (quota_in_str, UNLIMITED_STRING)
691           || (GNUNET_SYSERR ==
692               GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &quota_in)))
693         quota_in = UINT32_MAX;
694       GNUNET_free (quota_in_str);
695       GNUNET_asprintf (&quota_in_str, "%llu", quota_in);
696     }
697     else
698     {
699       FPRINTF (stderr,
700                "Inbound quota for network `%11s' not configured!\n",
701                GNUNET_ATS_print_network_type (c));
702       GNUNET_asprintf (&quota_in_str, "-");
703     }
704     GNUNET_free(entry_in);
705
706     FPRINTF (stdout,
707              _("Quota for network `%11s' (in/out): %10s / %10s\n"),
708              GNUNET_ATS_print_network_type (c),
709              quota_in_str,
710              quota_out_str);
711     GNUNET_free(quota_out_str);
712     GNUNET_free(quota_in_str);
713   }
714   return GNUNET_ATS_NetworkTypeCount;
715 }
716
717
718 /**
719  * Main function that will be run by the scheduler.
720  *
721  * @param cls closure
722  * @param args remaining command-line arguments
723  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
724  * @param my_cfg configuration
725  */
726 static void
727 run (void *cls,
728      char * const *args,
729      const char *cfgfile,
730      const struct GNUNET_CONFIGURATION_Handle *my_cfg)
731 {
732   struct GNUNET_PeerIdentity pid;
733   struct GNUNET_PeerIdentity cpid;
734   unsigned int c;
735   unsigned int type;
736
737   cfg = (struct GNUNET_CONFIGURATION_Handle *) my_cfg;
738   addresses = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
739   stat_results = 0;
740
741   c = 0;
742   if (NULL != opt_pid_str)
743   {
744     if (GNUNET_OK !=
745         GNUNET_CRYPTO_eddsa_public_key_from_string (opt_pid_str,
746                                                     strlen (opt_pid_str),
747                                                     &pid.public_key))
748     {
749       FPRINTF (stderr,
750                _("Failed to parse peer identity `%s'\n"),
751                opt_pid_str);
752       return;
753     }
754   }
755   if (NULL != cpid_str)
756   {
757     if (GNUNET_OK !=
758         GNUNET_CRYPTO_eddsa_public_key_from_string (cpid_str,
759                                                     strlen (cpid_str),
760                                                     &cpid.public_key))
761     {
762       FPRINTF (stderr,
763                _("Failed to parse peer identity `%s'\n"),
764                cpid_str);
765       return;
766     }
767     c++;
768   }
769
770   c += opt_list_all + opt_list_used + opt_monitor + opt_set_pref;
771
772   if (1 < c)
773   {
774     FPRINTF (stderr,
775              _("Please select one operation: %s or %s or %s or %s or %s\n"),
776              "--used",
777              "--all",
778              "--monitor",
779              "--preference",
780              "--quotas");
781     return;
782   }
783   if (0 == c)
784     opt_list_used = GNUNET_YES; /* set default */
785   if (opt_print_quotas)
786   {
787     ret = print_quotas (cfg);
788     return;
789   }
790   if (opt_list_all)
791   {
792     ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
793     if (NULL == ph)
794     {
795       FPRINTF (stderr,
796                "%s",
797                _("Cannot connect to ATS service, exiting...\n"));
798       return;
799     }
800     alh = GNUNET_ATS_performance_list_addresses (ph,
801                                                  (NULL == opt_pid_str) ? NULL : &pid,
802                                                  GNUNET_YES,
803                                                  &ats_perf_cb, NULL);
804     if (NULL == alh)
805     {
806       FPRINTF (stderr,
807                "%s",
808                _("Cannot issue request to ATS service, exiting...\n"));
809       shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
810       return;
811     }
812     shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
813                                                   &end,
814                                                   NULL);
815     return;
816   }
817   if (opt_list_used)
818   {
819     ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
820     if (NULL == ph)
821       FPRINTF (stderr,
822                "%s",
823                _("Cannot connect to ATS service, exiting...\n"));
824
825     alh = GNUNET_ATS_performance_list_addresses (ph,
826                                                  (NULL == opt_pid_str)
827                                                  ? NULL
828                                                  : &pid,
829                                                  GNUNET_NO,
830                                                  &ats_perf_cb, NULL);
831     if (NULL == alh)
832     {
833       FPRINTF (stderr,
834                "%s",
835                _("Cannot issue request to ATS service, exiting...\n"));
836       shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
837       return;
838     }
839     shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
840                                              &end,
841                                              NULL);
842     return;
843   }
844   if (opt_monitor)
845   {
846     ph = GNUNET_ATS_performance_init (cfg,
847                                       &ats_perf_mon_cb,
848                                       NULL);
849     if (NULL == ph)
850       FPRINTF (stderr,
851                "%s",
852                _("Cannot connect to ATS service, exiting...\n"));
853     shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
854                                                   &end,
855                                                   NULL);
856     return;
857   }
858   if (opt_set_pref)
859   {
860     if (NULL == opt_type_str)
861     {
862       FPRINTF (stderr,
863                "%s",
864                _("No preference type given!\n"));
865       return;
866     }
867     if (NULL == opt_pid_str)
868     {
869       FPRINTF (stderr,
870                "%s",
871                _("No peer given!\n"));
872       return;
873     }
874
875     for (c = 0; c < strlen (opt_type_str); c++)
876     {
877       if (isupper (opt_type_str[c]))
878         opt_type_str[c] = tolower (opt_type_str[c]);
879     }
880
881     if (0 == strcasecmp ("latency", opt_type_str))
882       type = GNUNET_ATS_PREFERENCE_LATENCY;
883     else if (0 == strcasecmp ("bandwidth", opt_type_str))
884       type = GNUNET_ATS_PREFERENCE_BANDWIDTH;
885     else
886     {
887       FPRINTF (stderr,
888                "%s",
889                _("Valid type required\n"));
890       return;
891     }
892
893     /* set */
894     ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
895     if (NULL == ph)
896       FPRINTF (stderr,
897                "%s",
898                _("Cannot connect to ATS service, exiting...\n"));
899
900     GNUNET_ATS_performance_change_preference (ph,
901                                               &pid,
902                                               type,
903                                               (double) opt_pref_value,
904                                               GNUNET_ATS_PREFERENCE_END);
905
906     shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
907                                                   &end,
908                                                   NULL);
909     return;
910   }
911   if (NULL != cpid_str)
912   {
913     ats_ch = GNUNET_ATS_connectivity_init (cfg);
914     ats_sh = GNUNET_ATS_connectivity_suggest (ats_ch,
915                                               &cpid,
916                                               1000);
917     shutdown_task
918       = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
919                                       &end,
920                                       NULL);
921     return;
922   }
923   ret = 1;
924 }
925
926
927 /**
928  * The main function.
929  *
930  * @param argc number of arguments from the command line
931  * @param argv command line arguments
932  * @return 0 ok, 1 on error
933  */
934 int
935 main (int argc,
936       char * const *argv)
937 {
938   int res;
939
940   opt_resolve_addresses_numeric = GNUNET_NO;
941   opt_monitor = GNUNET_NO;
942   opt_list_all = GNUNET_NO;
943   opt_list_used = GNUNET_NO;
944   opt_set_pref = GNUNET_NO;
945   stat_pending = 0;
946   stat_receive_done = GNUNET_NO;
947   opt_type_str = NULL;
948
949   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
950     { 'u', "used", NULL,
951       gettext_noop ("get list of active addresses currently used"), 0,
952       &GNUNET_GETOPT_set_one, &opt_list_used },
953     { 'a', "all", NULL, gettext_noop ("get list of all active addresses"), 0,
954       &GNUNET_GETOPT_set_one, &opt_list_all },
955     { 'C', "connect", "PEER",
956       gettext_noop ("connect to PEER"), 1,
957       &GNUNET_GETOPT_set_string, &cpid_str },
958     { 'n', "numeric", NULL,
959       gettext_noop ("do not resolve IP addresses to hostnames"), 0,
960       &GNUNET_GETOPT_set_one, &opt_resolve_addresses_numeric },
961     { 'm', "monitor", NULL, gettext_noop ("monitor mode"), 0,
962       &GNUNET_GETOPT_set_one, &opt_monitor },
963     { 'p', "preference", NULL, gettext_noop ("set preference for the given peer"),
964       0, &GNUNET_GETOPT_set_one, &opt_set_pref },
965     { 'q', "quotas", NULL, gettext_noop ("print all configured quotas"), 0,
966       &GNUNET_GETOPT_set_one, &opt_print_quotas },
967     { 'i', "id", "TYPE", gettext_noop ("peer id"), 1, &GNUNET_GETOPT_set_string,
968       &opt_pid_str },
969     { 't', "type", "TYPE",
970       gettext_noop ("preference type to set: latency | bandwidth"), 1,
971       &GNUNET_GETOPT_set_string, &opt_type_str },
972     { 'k', "value", "VALUE", gettext_noop ("preference value"), 1,
973       &GNUNET_GETOPT_set_uint, &opt_pref_value },
974     { 'V', "verbose", NULL,
975       gettext_noop ("verbose output (include ATS address properties)"), 0,
976       &GNUNET_GETOPT_set_one, &opt_verbose },
977     GNUNET_GETOPT_OPTION_END
978   };
979
980   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
981     return 2;
982
983   res = GNUNET_PROGRAM_run (argc, argv,
984                             "gnunet-ats",
985                             gettext_noop ("Print information about ATS state"),
986                             options,
987                             &run, NULL);
988   GNUNET_free_non_null(opt_pid_str);
989   GNUNET_free_non_null(opt_type_str);
990   GNUNET_free((void *) argv);
991
992   if (GNUNET_OK == res)
993     return ret;
994   else
995     return 1;
996 }
997
998 /* end of gnunet-ats.c */