Merge branch 'identity_abe' into identity_oidc
[oweals/gnunet.git] / src / ats-tool / gnunet-ats.c
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2009--2015 GNUnet e.V.
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  */
269 static void
270 end (void *cls)
271 {
272   struct PendingResolutions * pr;
273   struct PendingResolutions * next;
274   unsigned int pending;
275
276   if (NULL != alh)
277   {
278     GNUNET_ATS_performance_list_addresses_cancel (alh);
279     alh = NULL;
280   }
281
282   if (NULL != ph)
283   {
284     GNUNET_ATS_performance_done (ph);
285     ph = NULL;
286   }
287
288   pending = 0;
289   next = head;
290   while (NULL != (pr = next))
291   {
292     next = pr->next;
293     GNUNET_CONTAINER_DLL_remove(head, tail, pr);
294     GNUNET_TRANSPORT_address_to_string_cancel (pr->tats_ctx);
295     GNUNET_free(pr->address);
296     GNUNET_free(pr);
297     pending++;
298   }
299   GNUNET_CONTAINER_multipeermap_iterate (addresses,
300                                          &free_addr_it,
301                                          NULL);
302   GNUNET_CONTAINER_multipeermap_destroy (addresses);
303   addresses = NULL;
304
305   if (0 < pending)
306     FPRINTF (stdout,
307              _("%u address resolutions had a timeout\n"),
308              pending);
309   if (opt_list_used || opt_list_all)
310     FPRINTF (stdout,
311              _("ATS returned stat_results for %u addresses\n"),
312              stat_results);
313
314   if (NULL != ats_sh)
315   {
316     GNUNET_ATS_connectivity_suggest_cancel (ats_sh);
317     ats_sh = NULL;
318   }
319   if (NULL != ats_ch)
320   {
321     GNUNET_ATS_connectivity_done (ats_ch);
322     ats_ch = NULL;
323   }
324   ret = 0;
325 }
326
327
328 /**
329  * Function to call with a textual representation of an address.  This
330  * function will be called several times with different possible
331  * textual representations, and a last time with @a address being NULL
332  * to signal the end of the iteration.  Note that @a address NULL
333  * always is the last call, regardless of the value in @a res.
334  *
335  * @param cls closure, a `struct PendingResolutions *`
336  * @param address NULL on end of iteration,
337  *        otherwise 0-terminated printable UTF-8 string,
338  *        in particular an empty string if @a res is #GNUNET_NO
339  * @param res result of the address to string conversion:
340  *        if #GNUNET_OK: conversion successful
341  *        if #GNUNET_NO: address was invalid (or not supported)
342  *        if #GNUNET_SYSERR: communication error (IPC error)
343  */
344 static void
345 transport_addr_to_str_cb (void *cls,
346                           const char *address,
347                           int res)
348 {
349   struct PendingResolutions *pr = cls;
350
351   if (NULL == address)
352   {
353     /* We're done */
354     GNUNET_CONTAINER_DLL_remove (head,
355                                  tail,
356                                  pr);
357     GNUNET_free (pr->address);
358     GNUNET_free (pr);
359     stat_pending--;
360
361     if ((GNUNET_YES == stat_receive_done) && (0 == stat_pending))
362     {
363       /* All messages received and no resolutions pending*/
364       if (shutdown_task != NULL)
365         GNUNET_SCHEDULER_cancel (shutdown_task);
366       shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
367     }
368     return;
369   }
370   switch (res)
371   {
372   case GNUNET_SYSERR:
373     FPRINTF (stderr,
374              "Failed to convert address for peer `%s' plugin `%s' length %u to string (communication error)\n",
375              GNUNET_i2s (&pr->address->peer),
376              pr->address->transport_name,
377              (unsigned int) pr->address->address_length);
378     return;
379   case GNUNET_NO:
380     FPRINTF (stderr,
381              "Failed to convert address for peer `%s' plugin `%s' length %u to string (address invalid or not supported)\n",
382              GNUNET_i2s (&pr->address->peer),
383              pr->address->transport_name,
384              (unsigned int) pr->address->address_length);
385     return;
386   case GNUNET_OK:
387     /* continues below */
388     break;
389   default:
390     GNUNET_break (0);
391     return;
392   }
393
394   FPRINTF (stdout,
395            _("Peer `%s' plugin `%s', address `%s', `%s' bw out: %u Bytes/s, bw in %u Bytes/s, %s\n"),
396            GNUNET_i2s (&pr->address->peer),
397            pr->address->transport_name,
398            address,
399            GNUNET_ATS_print_network_type (pr->properties.scope),
400            ntohl (pr->bandwidth_out.value__),
401            ntohl (pr->bandwidth_in.value__),
402            pr->active ? _("active ") : _("inactive "));
403 }
404
405
406 /**
407  * Closure for #find_address_it().
408  */
409 struct AddressFindCtx
410 {
411   /**
412    * Address we are looking for.
413    */
414   const struct GNUNET_HELLO_Address *src;
415
416   /**
417    * Where to write the `struct ATSAddress` if we found one that matches.
418    */
419   struct ATSAddress *res;
420 };
421
422
423 /**
424  * Find address corresponding to a given peer.
425  *
426  * @param cls the `struct AddressFindCtx *`
427  * @param key peer identity
428  * @param value the `struct ATSAddress *` for an existing address
429  * @return #GNUNET_NO if we found a match, #GNUNET_YES if not
430  */
431 static int
432 find_address_it (void *cls,
433                  const struct GNUNET_PeerIdentity *key,
434                  void *value)
435 {
436   struct AddressFindCtx *actx = cls;
437   struct ATSAddress *exist = value;
438
439   if (0 == GNUNET_HELLO_address_cmp (actx->src, exist->address))
440   {
441     actx->res = exist;
442     return GNUNET_NO;
443   }
444   return GNUNET_YES;
445 }
446
447
448
449 /**
450  * Signature of a function that is called with QoS information about an address.
451  *
452  * @param cls closure (NULL)
453  * @param address the address, NULL if ATS service was disconnected
454  * @param active #GNUNET_YES if this address is actively used
455  *        to maintain a connection to a peer;
456  *        #GNUNET_NO if the address is not actively used;
457  *        #GNUNET_SYSERR if this address is no longer available for ATS
458  * @param bandwidth_out assigned outbound bandwidth for the connection
459  * @param bandwidth_in assigned inbound bandwidth for the connection
460  * @param prop performance data for the address (as far as known)
461  */
462 static void
463 ats_perf_mon_cb (void *cls,
464                  const struct GNUNET_HELLO_Address *address,
465                  int active,
466                  struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
467                  struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
468                  const struct GNUNET_ATS_Properties *prop)
469 {
470   struct PendingResolutions *pr;
471   struct PendingResolutions *cur;
472   struct PendingResolutions *next;
473
474   if (NULL == address)
475   {
476     /* ATS service temporarily disconnected, remove current state */
477     next = head;
478     for (cur = next; NULL != cur; cur = next)
479     {
480       next = cur->next;
481       GNUNET_CONTAINER_DLL_remove (head, tail, cur);
482       GNUNET_TRANSPORT_address_to_string_cancel (cur->tats_ctx);
483       GNUNET_HELLO_address_free (cur->address);
484       GNUNET_free (cur);
485     }
486     GNUNET_CONTAINER_multipeermap_iterate (addresses,
487                                            &free_addr_it,
488                                            NULL);
489     return;
490   }
491   if (GNUNET_SYSERR == active)
492   {
493     /* remove address */
494     struct AddressFindCtx actx;
495
496     actx.src = address;
497     actx.res = NULL;
498     GNUNET_CONTAINER_multipeermap_get_multiple (addresses,
499                                                 &address->peer,
500                                                 &find_address_it,
501                                                 &actx);
502     if (NULL == actx.res)
503     {
504       GNUNET_break (0);
505       return;
506     }
507     GNUNET_break(GNUNET_OK ==
508                  GNUNET_CONTAINER_multipeermap_remove (addresses,
509                                                        &address->peer,
510                                                        actx.res));
511     FPRINTF (stdout,
512              _("Removed address of peer `%s' with plugin `%s'\n"),
513              GNUNET_i2s (&address->peer),
514              actx.res->address->transport_name);
515     GNUNET_HELLO_address_free (actx.res);
516     return;
517   }
518
519   if (GNUNET_NO == opt_verbose)
520   {
521     struct AddressFindCtx actx;
522     struct ATSAddress *a;
523
524     actx.src = address;
525     actx.res = NULL;
526     GNUNET_CONTAINER_multipeermap_get_multiple (addresses,
527                                                 &address->peer,
528                                                 &find_address_it,
529                                                 &actx);
530     if ((NULL != actx.res))
531     {
532       if ((bandwidth_in.value__ == actx.res->bandwidth_in.value__) &&
533           (bandwidth_out.value__ == actx.res->bandwidth_out.value__) &&
534           (active == actx.res->active))
535       {
536         return; /* Nothing to do here */
537       }
538       else
539       {
540         actx.res->bandwidth_in = bandwidth_in;
541         actx.res->bandwidth_out = bandwidth_out;
542       }
543     }
544     else
545     {
546       a = GNUNET_new (struct ATSAddress);
547
548       a->address = GNUNET_HELLO_address_copy(address);
549       a->bandwidth_in = bandwidth_in;
550       a->bandwidth_out = bandwidth_out;
551       a->active = active;
552       GNUNET_CONTAINER_multipeermap_put (addresses,
553                                          &address->peer,
554                                          a,
555                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
556     }
557   }
558
559   pr = GNUNET_new (struct PendingResolutions);
560   pr->properties = *prop;
561   pr->address = GNUNET_HELLO_address_copy (address);
562   pr->bandwidth_in = bandwidth_in;
563   pr->bandwidth_out = bandwidth_out;
564   pr->active = active;
565   pr->tats_ctx = GNUNET_TRANSPORT_address_to_string (cfg, address,
566                                                      opt_resolve_addresses_numeric,
567                                                      GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
568                                                      &transport_addr_to_str_cb,
569                                                      pr);
570   GNUNET_CONTAINER_DLL_insert (head, tail, pr);
571   stat_results++;
572   stat_pending++;
573 }
574
575
576 /**
577  * Signature of a function that is called with QoS information about an address.
578  *
579  * @param cls closure (NULL)
580  * @param address the address, NULL if ATS service was disconnected
581  * @param active is this address actively used to maintain a connection
582           to a peer
583  * @param bandwidth_out assigned outbound bandwidth for the connection
584  * @param bandwidth_in assigned inbound bandwidth for the connection
585  * @param prop performance data for the address (as far as known)
586  */
587 static void
588 ats_perf_cb (void *cls,
589              const struct GNUNET_HELLO_Address *address,
590              int active,
591              struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
592              struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
593              const struct GNUNET_ATS_Properties *prop)
594 {
595   struct PendingResolutions *pr;
596
597   if (NULL == address)
598   {
599     /* All messages received */
600     stat_receive_done = GNUNET_YES;
601     alh = NULL;
602     if (0 == stat_pending)
603     {
604       /* All messages received and no resolutions pending*/
605       if (shutdown_task != NULL)
606         GNUNET_SCHEDULER_cancel (shutdown_task);
607       shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
608     }
609     return;
610   }
611
612   pr = GNUNET_new (struct PendingResolutions);
613   pr->properties = *prop;
614   pr->address = GNUNET_HELLO_address_copy (address);
615   pr->bandwidth_in = bandwidth_in;
616   pr->bandwidth_out = bandwidth_out;
617   pr->active = active;
618   pr->tats_ctx = GNUNET_TRANSPORT_address_to_string (cfg, address,
619                                                      opt_resolve_addresses_numeric,
620                                                      GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
621                                                      &transport_addr_to_str_cb, pr);
622   GNUNET_CONTAINER_DLL_insert (head, tail, pr);
623   stat_results++;
624   stat_pending++;
625 }
626
627
628 /**
629  * Print information about the quotas configured for the various
630  * network scopes.
631  *
632  * @param cfg configuration to obtain quota information from
633  * @return total number of ATS network types known
634  */
635 static unsigned int
636 print_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg)
637 {
638   char * entry_in = NULL;
639   char * entry_out = NULL;
640   char * quota_out_str;
641   char * quota_in_str;
642   unsigned long long int quota_out;
643   unsigned long long int quota_in;
644   int c;
645
646   for (c = 0; (c < GNUNET_ATS_NetworkTypeCount); c++)
647   {
648
649     GNUNET_asprintf (&entry_out,
650                      "%s_QUOTA_OUT",
651                      GNUNET_ATS_print_network_type (c));
652     GNUNET_asprintf (&entry_in,
653                      "%s_QUOTA_IN",
654                      GNUNET_ATS_print_network_type (c));
655
656     /* quota out */
657     if (GNUNET_OK ==
658         GNUNET_CONFIGURATION_get_value_string (cfg,
659                                                "ats",
660                                                entry_out,
661                                                &quota_out_str))
662     {
663       if (0 == strcmp (quota_out_str, UNLIMITED_STRING)
664           || (GNUNET_SYSERR ==
665               GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str,
666                                                   &quota_out)))
667         quota_out = UINT32_MAX;
668
669       GNUNET_free(quota_out_str);
670       GNUNET_asprintf (&quota_out_str, "%llu", quota_out);
671     }
672     else
673     {
674       FPRINTF (stderr,
675                "Outbound quota for network `%11s' not configured!\n",
676                GNUNET_ATS_print_network_type (c));
677       GNUNET_asprintf (&quota_out_str, "-");
678     }
679     GNUNET_free (entry_out);
680
681     /* quota in */
682     if (GNUNET_OK ==
683         GNUNET_CONFIGURATION_get_value_string (cfg,
684                                                "ats",
685                                                entry_in,
686                                                &quota_in_str))
687     {
688       if (0 == strcmp (quota_in_str, UNLIMITED_STRING)
689           || (GNUNET_SYSERR ==
690               GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &quota_in)))
691         quota_in = UINT32_MAX;
692       GNUNET_free (quota_in_str);
693       GNUNET_asprintf (&quota_in_str, "%llu", quota_in);
694     }
695     else
696     {
697       FPRINTF (stderr,
698                "Inbound quota for network `%11s' not configured!\n",
699                GNUNET_ATS_print_network_type (c));
700       GNUNET_asprintf (&quota_in_str, "-");
701     }
702     GNUNET_free(entry_in);
703
704     FPRINTF (stdout,
705              _("Quota for network `%11s' (in/out): %10s / %10s\n"),
706              GNUNET_ATS_print_network_type (c),
707              quota_in_str,
708              quota_out_str);
709     GNUNET_free(quota_out_str);
710     GNUNET_free(quota_in_str);
711   }
712   return GNUNET_ATS_NetworkTypeCount;
713 }
714
715
716 /**
717  * Main function that will be run by the scheduler.
718  *
719  * @param cls closure
720  * @param args remaining command-line arguments
721  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
722  * @param my_cfg configuration
723  */
724 static void
725 run (void *cls,
726      char * const *args,
727      const char *cfgfile,
728      const struct GNUNET_CONFIGURATION_Handle *my_cfg)
729 {
730   struct GNUNET_PeerIdentity pid;
731   struct GNUNET_PeerIdentity cpid;
732   unsigned int c;
733   unsigned int type;
734
735   cfg = (struct GNUNET_CONFIGURATION_Handle *) my_cfg;
736   addresses = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
737   stat_results = 0;
738
739   c = 0;
740   if (NULL != opt_pid_str)
741   {
742     if (GNUNET_OK !=
743         GNUNET_CRYPTO_eddsa_public_key_from_string (opt_pid_str,
744                                                     strlen (opt_pid_str),
745                                                     &pid.public_key))
746     {
747       FPRINTF (stderr,
748                _("Failed to parse peer identity `%s'\n"),
749                opt_pid_str);
750       return;
751     }
752   }
753   if (NULL != cpid_str)
754   {
755     if (GNUNET_OK !=
756         GNUNET_CRYPTO_eddsa_public_key_from_string (cpid_str,
757                                                     strlen (cpid_str),
758                                                     &cpid.public_key))
759     {
760       FPRINTF (stderr,
761                _("Failed to parse peer identity `%s'\n"),
762                cpid_str);
763       return;
764     }
765     c++;
766   }
767
768   c += opt_list_all + opt_list_used + opt_monitor + opt_set_pref;
769
770   if (1 < c)
771   {
772     FPRINTF (stderr,
773              _("Please select one operation: %s or %s or %s or %s or %s\n"),
774              "--used",
775              "--all",
776              "--monitor",
777              "--preference",
778              "--quotas");
779     return;
780   }
781   if (0 == c)
782     opt_list_used = GNUNET_YES; /* set default */
783   if (opt_print_quotas)
784   {
785     ret = print_quotas (cfg);
786     return;
787   }
788   if (opt_list_all)
789   {
790     ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
791     if (NULL == ph)
792     {
793       FPRINTF (stderr,
794                "%s",
795                _("Cannot connect to ATS service, exiting...\n"));
796       return;
797     }
798     alh = GNUNET_ATS_performance_list_addresses (ph,
799                                                  (NULL == opt_pid_str) ? NULL : &pid,
800                                                  GNUNET_YES,
801                                                  &ats_perf_cb, NULL);
802     if (NULL == alh)
803     {
804       FPRINTF (stderr,
805                "%s",
806                _("Cannot issue request to ATS service, exiting...\n"));
807       shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
808       return;
809     }
810     shutdown_task = GNUNET_SCHEDULER_add_shutdown (&end,
811                                                    NULL);
812     return;
813   }
814   if (opt_list_used)
815   {
816     ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
817     if (NULL == ph)
818       FPRINTF (stderr,
819                "%s",
820                _("Cannot connect to ATS service, exiting...\n"));
821
822     alh = GNUNET_ATS_performance_list_addresses (ph,
823                                                  (NULL == opt_pid_str)
824                                                  ? NULL
825                                                  : &pid,
826                                                  GNUNET_NO,
827                                                  &ats_perf_cb, NULL);
828     if (NULL == alh)
829     {
830       FPRINTF (stderr,
831                "%s",
832                _("Cannot issue request to ATS service, exiting...\n"));
833       shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
834       return;
835     }
836     shutdown_task = GNUNET_SCHEDULER_add_shutdown (&end,
837                                                    NULL);
838     return;
839   }
840   if (opt_monitor)
841   {
842     ph = GNUNET_ATS_performance_init (cfg,
843                                       &ats_perf_mon_cb,
844                                       NULL);
845     shutdown_task = GNUNET_SCHEDULER_add_shutdown (&end,
846                                                    NULL);
847     if (NULL == ph)
848     {
849       FPRINTF (stderr,
850                "%s",
851                _("Cannot connect to ATS service, exiting...\n"));
852       GNUNET_SCHEDULER_shutdown ();
853     }
854     return;
855   }
856   if (opt_set_pref)
857   {
858     if (NULL == opt_type_str)
859     {
860       FPRINTF (stderr,
861                "%s",
862                _("No preference type given!\n"));
863       return;
864     }
865     if (NULL == opt_pid_str)
866     {
867       FPRINTF (stderr,
868                "%s",
869                _("No peer given!\n"));
870       return;
871     }
872
873     for (c = 0; c < strlen (opt_type_str); c++)
874     {
875       if (isupper ((unsigned char) opt_type_str[c]))
876         opt_type_str[c] = tolower ((unsigned char) opt_type_str[c]);
877     }
878
879     if (0 == strcasecmp ("latency", opt_type_str))
880       type = GNUNET_ATS_PREFERENCE_LATENCY;
881     else if (0 == strcasecmp ("bandwidth", opt_type_str))
882       type = GNUNET_ATS_PREFERENCE_BANDWIDTH;
883     else
884     {
885       FPRINTF (stderr,
886                "%s",
887                _("Valid type required\n"));
888       return;
889     }
890
891     /* set */
892     ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
893     if (NULL == ph)
894       FPRINTF (stderr,
895                "%s",
896                _("Cannot connect to ATS service, exiting...\n"));
897
898     GNUNET_ATS_performance_change_preference (ph,
899                                               &pid,
900                                               type,
901                                               (double) opt_pref_value,
902                                               GNUNET_ATS_PREFERENCE_END);
903
904     shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
905                                                   &end,
906                                                   NULL);
907     return;
908   }
909   if (NULL != cpid_str)
910   {
911     ats_ch = GNUNET_ATS_connectivity_init (cfg);
912     ats_sh = GNUNET_ATS_connectivity_suggest (ats_ch,
913                                               &cpid,
914                                               1000);
915     shutdown_task
916       = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
917                                       &end,
918                                       NULL);
919     return;
920   }
921   ret = 1;
922 }
923
924
925 /**
926  * The main function.
927  *
928  * @param argc number of arguments from the command line
929  * @param argv command line arguments
930  * @return 0 ok, 1 on error
931  */
932 int
933 main (int argc,
934       char * const *argv)
935 {
936   int res;
937
938   opt_resolve_addresses_numeric = GNUNET_NO;
939   opt_monitor = GNUNET_NO;
940   opt_list_all = GNUNET_NO;
941   opt_list_used = GNUNET_NO;
942   opt_set_pref = GNUNET_NO;
943   stat_pending = 0;
944   stat_receive_done = GNUNET_NO;
945   opt_type_str = NULL;
946
947   struct GNUNET_GETOPT_CommandLineOption options[] = {
948     GNUNET_GETOPT_option_flag ('u',
949                                   "used",
950                                   gettext_noop ("get list of active addresses currently used"),
951                                   &opt_list_used),
952     GNUNET_GETOPT_option_flag ('a',
953                                   "all",
954                                   gettext_noop ("get list of all active addresses"),
955                                   &opt_list_all),
956
957     GNUNET_GETOPT_option_string ('C',
958                                  "connect",
959                                  NULL,
960                                  gettext_noop ("connect to PEER"),
961                                  &cpid_str),
962     GNUNET_GETOPT_option_flag ('n',
963                                   "numeric",
964                                   gettext_noop ("do not resolve IP addresses to hostnames"),
965                                   &opt_resolve_addresses_numeric),
966
967     GNUNET_GETOPT_option_flag ('m',
968                                   "monitor",
969                                   gettext_noop ("monitor mode"),
970                                   &opt_monitor),
971
972     GNUNET_GETOPT_option_flag ('p',
973                                   "preference",
974                                   gettext_noop ("set preference for the given peer"),
975                                   &opt_set_pref),
976
977     GNUNET_GETOPT_option_flag ('q',
978                                   "quotas",
979                                   gettext_noop ("print all configured quotas"),
980                                   &opt_print_quotas),
981     GNUNET_GETOPT_option_string ('i',
982                                  "id",
983                                  "TYPE",
984                                  gettext_noop ("peer id"),
985                                  &opt_pid_str),
986
987     GNUNET_GETOPT_option_string ('t',
988                                  "type",
989                                  "TYPE",
990                                  gettext_noop ("preference type to set: latency | bandwidth"),
991                                  &opt_type_str),
992
993     GNUNET_GETOPT_option_uint ('k',
994                                    "value",
995                                    "VALUE",
996                                    gettext_noop ("preference value"),
997                                    &opt_pref_value),
998
999     GNUNET_GETOPT_option_flag ('V',
1000                                   "verbose",
1001                                   gettext_noop ("verbose output (include ATS address properties)"),
1002                                   &opt_verbose),
1003     GNUNET_GETOPT_OPTION_END
1004   };
1005
1006   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1007     return 2;
1008
1009   res = GNUNET_PROGRAM_run (argc, argv,
1010                             "gnunet-ats",
1011                             gettext_noop ("Print information about ATS state"),
1012                             options,
1013                             &run, NULL);
1014   GNUNET_free_non_null(opt_pid_str);
1015   GNUNET_free_non_null(opt_type_str);
1016   GNUNET_free((void *) argv);
1017
1018   if (GNUNET_OK == res)
1019     return ret;
1020   else
1021     return 1;
1022 }
1023
1024 /* end of gnunet-ats.c */