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