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