reading alpha, beta from .conf
[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 struct GNUNET_SCHEDULER_Task * 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 != NULL)
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     return;
549   }
550
551   if (GNUNET_NO == opt_verbose)
552   {
553     struct AddressFindCtx actx;
554     struct ATSAddress *a;
555
556     actx.src = address;
557     actx.res = NULL;
558     GNUNET_CONTAINER_multipeermap_get_multiple (addresses, &address->peer,
559         &find_address_it, &actx);
560     if ((NULL != actx.res))
561     {
562       if ((bandwidth_in.value__ == actx.res->bandwidth_in.value__) &&
563           (bandwidth_out.value__ == actx.res->bandwidth_out.value__) &&
564           (active == actx.res->active))
565       {
566         return; /* Nothing to do here */
567       }
568       else
569       {
570         actx.res->bandwidth_in = bandwidth_in;
571         actx.res->bandwidth_out = bandwidth_out;
572       }
573     }
574     else
575     {
576       a = GNUNET_new (struct ATSAddress);
577
578       a->address = GNUNET_HELLO_address_copy(address);
579       a->bandwidth_in = bandwidth_in;
580       a->bandwidth_out = bandwidth_out;
581       a->active = active;
582       GNUNET_CONTAINER_multipeermap_put (addresses, &address->peer, a,
583           GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
584     }
585   }
586
587   pr = GNUNET_malloc (sizeof (struct PendingResolutions) +
588       ats_count * sizeof (struct GNUNET_ATS_Information));
589
590   pr->ats_count = ats_count;
591   pr->ats = (struct GNUNET_ATS_Information *) &pr[1];
592   if (ats_count > 0)
593     memcpy (pr->ats, ats, ats_count * sizeof(struct GNUNET_ATS_Information));
594   pr->address = GNUNET_HELLO_address_copy (address);
595   pr->bandwidth_in = bandwidth_in;
596   pr->bandwidth_out = bandwidth_out;
597   pr->active = active;
598   pr->tats_ctx = GNUNET_TRANSPORT_address_to_string (cfg, address,
599                                                      opt_resolve_addresses_numeric,
600                                                      GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
601                                                      &transport_addr_to_str_cb,
602                                                      pr);
603   GNUNET_CONTAINER_DLL_insert (head, tail, pr);
604   stat_results++;
605   stat_pending++;
606 }
607
608
609 /**
610  * Signature of a function that is called with QoS information about an address.
611  *
612  * @param cls closure (NULL)
613  * @param address the address, NULL if ATS service was disconnected
614  * @param active is this address actively used to maintain a connection
615           to a peer
616  * @param bandwidth_out assigned outbound bandwidth for the connection
617  * @param bandwidth_in assigned inbound bandwidth for the connection
618  * @param ats performance data for the address (as far as known)
619  * @param ats_count number of performance records in @a ats
620  */
621 static void
622 ats_perf_cb (void *cls,
623              const struct GNUNET_HELLO_Address *address,
624              int active,
625              struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
626              struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
627              const struct GNUNET_ATS_Information *ats,
628              uint32_t ats_count)
629 {
630   struct PendingResolutions *pr;
631
632   if (NULL == address)
633   {
634     /* All messages received */
635     stat_receive_done = GNUNET_YES;
636     alh = NULL;
637     if (0 == stat_pending)
638     {
639       /* All messages received and no resolutions pending*/
640       if (shutdown_task != NULL)
641         GNUNET_SCHEDULER_cancel (shutdown_task);
642       shutdown_task = GNUNET_SCHEDULER_add_now (end, NULL);
643     }
644     return;
645   }
646
647   pr = GNUNET_malloc (sizeof (struct PendingResolutions) +
648       ats_count * sizeof (struct GNUNET_ATS_Information));
649
650   pr->ats_count = ats_count;
651   pr->ats = (struct GNUNET_ATS_Information *) &pr[1];
652   if (ats_count > 0)
653     memcpy (pr->ats, ats, ats_count * sizeof(struct GNUNET_ATS_Information));
654   pr->address = GNUNET_HELLO_address_copy (address);
655   pr->bandwidth_in = bandwidth_in;
656   pr->bandwidth_out = bandwidth_out;
657   pr->active = active;
658   pr->tats_ctx = GNUNET_TRANSPORT_address_to_string (cfg, address,
659                                                      opt_resolve_addresses_numeric,
660                                                      GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
661                                                      &transport_addr_to_str_cb, pr);
662   GNUNET_CONTAINER_DLL_insert (head, tail, pr);
663   stat_results++;
664   stat_pending++;
665 }
666
667
668 /**
669  * Print information about the quotas configured for the various
670  * network scopes.
671  *
672  * @param cfg configuration to obtain quota information from
673  * @return total number of ATS network types known
674  */
675 static unsigned int
676 print_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg)
677 {
678   char *network_str[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkTypeString;
679   char * entry_in = NULL;
680   char * entry_out = NULL;
681   char * quota_out_str;
682   char * quota_in_str;
683   unsigned long long int quota_out;
684   unsigned long long int quota_in;
685   int c;
686
687   for (c = 0; (c < GNUNET_ATS_NetworkTypeCount); c++)
688   {
689
690     GNUNET_asprintf (&entry_out,
691                      "%s_QUOTA_OUT",
692                      network_str[c]);
693     GNUNET_asprintf (&entry_in,
694                      "%s_QUOTA_IN",
695                      network_str[c]);
696
697     /* quota out */
698     if (GNUNET_OK ==
699         GNUNET_CONFIGURATION_get_value_string (cfg,
700                                                "ats",
701                                                entry_out,
702                                                &quota_out_str))
703     {
704       if (0 == strcmp (quota_out_str, UNLIMITED_STRING)
705           || (GNUNET_SYSERR ==
706               GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str,
707                                                   &quota_out)))
708         quota_out = UINT32_MAX;
709
710       GNUNET_free(quota_out_str);
711       GNUNET_asprintf (&quota_out_str, "%llu", quota_out);
712     }
713     else
714     {
715       FPRINTF (stderr,
716                "Outbound quota for network `%11s' not configured!\n",
717                network_str[c]);
718       GNUNET_asprintf (&quota_out_str, "-");
719     }
720     GNUNET_free(entry_out);
721
722     /* quota in */
723     if (GNUNET_OK ==
724         GNUNET_CONFIGURATION_get_value_string (cfg,
725                                                "ats",
726                                                entry_in,
727                                                &quota_in_str))
728     {
729       if (0 == strcmp (quota_in_str, UNLIMITED_STRING)
730           || (GNUNET_SYSERR ==
731               GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &quota_in)))
732         quota_in = UINT32_MAX;
733       GNUNET_free(quota_in_str);
734       GNUNET_asprintf (&quota_in_str, "%llu", quota_in);
735     }
736     else
737     {
738       FPRINTF (stderr,
739                "Inbound quota for network `%11s' not configured!\n",
740                network_str[c]);
741       GNUNET_asprintf (&quota_in_str, "-");
742     }
743     GNUNET_free(entry_in);
744
745     FPRINTF (stderr,
746              _("Quota for network `%11s' (in/out): %10s / %10s\n"),
747              network_str[c],
748              quota_in_str,
749              quota_out_str);
750     GNUNET_free(quota_out_str);
751     GNUNET_free(quota_in_str);
752   }
753   return GNUNET_ATS_NetworkTypeCount;
754 }
755
756
757 /**
758  * Function called with the result from the test if ATS is
759  * running.  Runs the actual main logic.
760  *
761  * @param cls the `struct GNUNET_CONFIGURATION_Handle *`
762  * @param result result of the test, #GNUNET_YES if ATS is running
763  */
764 static void
765 testservice_ats (void *cls,
766                  int result)
767 {
768   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
769   struct GNUNET_PeerIdentity pid;
770   unsigned int c;
771   unsigned int type;
772
773   addresses = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
774
775   if (GNUNET_YES != result)
776   {
777     FPRINTF (stderr,
778              _("Service `%s' is not running\n"),
779              "ats");
780     return;
781   }
782
783   stat_results = 0;
784
785   if (NULL != opt_pid_str)
786   {
787     if (GNUNET_OK
788         != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_pid_str,
789             strlen (opt_pid_str), &pid.public_key))
790     {
791       FPRINTF (stderr,
792                _("Failed to parse peer identity `%s'\n"),
793                opt_pid_str);
794       return;
795     }
796   }
797
798   c = opt_list_all + opt_list_used + opt_monitor + opt_set_pref;
799   if ((1 < c))
800   {
801     FPRINTF (stderr,
802              _("Please select one operation : %s or %s or %s or %s or %s\n"),
803              "--used",
804              "--all",
805              "--monitor",
806              "--preference",
807              "--quotas");
808     return;
809   }
810   if ((0 == c))
811     opt_list_used = GNUNET_YES; /* set default */
812   if (opt_print_quotas)
813   {
814     ret = print_quotas (cfg);
815     return;
816   }
817   if (opt_list_all)
818   {
819     ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
820     if (NULL == ph)
821     {
822       FPRINTF (stderr,
823                "%s",
824                _("Cannot connect to ATS service, exiting...\n"));
825       return;
826     }
827
828     alh = GNUNET_ATS_performance_list_addresses (ph,
829                                                  (NULL == opt_pid_str) ? NULL : &pid,
830                                                  GNUNET_YES,
831                                                  &ats_perf_cb, NULL);
832     if (NULL == alh)
833     {
834       FPRINTF (stderr,
835                "%s",
836                _("Cannot issue request to ATS service, exiting...\n"));
837       shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
838       return;
839     }
840     shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
841                                              &end,
842                                              NULL);
843   }
844   else if (opt_list_used)
845   {
846     ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
847     if (NULL == ph)
848       FPRINTF (stderr,
849                "%s",
850                _("Cannot connect to ATS service, exiting...\n"));
851
852     alh = GNUNET_ATS_performance_list_addresses (ph,
853                                                  (NULL == opt_pid_str)
854                                                  ? NULL
855                                                  : &pid,
856                                                  GNUNET_NO,
857                                                  &ats_perf_cb, NULL);
858     if (NULL == alh)
859     {
860       FPRINTF (stderr,
861                "%s",
862                _("Cannot issue request to ATS service, exiting...\n"));
863       shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
864       return;
865     }
866     shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
867                                              &end,
868                                              NULL);
869   }
870   else if (opt_monitor)
871   {
872     ph = GNUNET_ATS_performance_init (cfg,
873                                       &ats_perf_mon_cb,
874                                       NULL);
875     if (NULL == ph)
876       FPRINTF (stderr,
877                "%s",
878                _("Cannot connect to ATS service, exiting...\n"));
879     shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
880                                              &end,
881                                              NULL);
882
883   }
884   else if (opt_set_pref)
885   {
886     if (NULL == opt_type_str)
887     {
888       FPRINTF (stderr,
889                "%s",
890                _("No preference type given!\n"));
891       return;
892     }
893     if (NULL == opt_pid_str)
894     {
895       FPRINTF (stderr,
896                "%s",
897                _("No peer given!\n"));
898       return;
899     }
900
901     for (c = 0; c < strlen (opt_type_str); c++)
902     {
903       if (isupper (opt_type_str[c]))
904         opt_type_str[c] = tolower (opt_type_str[c]);
905     }
906
907     if (0 == strcasecmp ("latency", opt_type_str))
908       type = GNUNET_ATS_PREFERENCE_LATENCY;
909     else if (0 == strcasecmp ("bandwidth", opt_type_str))
910       type = GNUNET_ATS_PREFERENCE_BANDWIDTH;
911     else
912     {
913       FPRINTF (stderr,
914                "%s",
915                _("Valid type required\n"));
916       return;
917     }
918
919     /* set */
920     ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
921     if (NULL == ph)
922       FPRINTF (stderr,
923                "%s",
924                _("Cannot connect to ATS service, exiting...\n"));
925
926     GNUNET_ATS_performance_change_preference (ph, &pid, type, (double) opt_pref_value,
927                                               GNUNET_ATS_PREFERENCE_END);
928
929     shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
930                                              &end,
931                                              NULL);
932   }
933   ret = 1;
934 }
935
936
937 /**
938  * Main function that will be run by the scheduler.
939  *
940  * @param cls closure
941  * @param args remaining command-line arguments
942  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
943  * @param my_cfg configuration
944  */
945 static void
946 run (void *cls,
947      char * const *args,
948      const char *cfgfile,
949      const struct GNUNET_CONFIGURATION_Handle *my_cfg)
950 {
951   cfg = (struct GNUNET_CONFIGURATION_Handle *) my_cfg;
952   GNUNET_CLIENT_service_test ("ats", cfg,
953       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
954       &testservice_ats, (void *) cfg);
955 }
956
957
958 /**
959  * The main function.
960  *
961  * @param argc number of arguments from the command line
962  * @param argv command line arguments
963  * @return 0 ok, 1 on error
964  */
965 int
966 main (int argc,
967       char * const *argv)
968 {
969   int res;
970
971   opt_resolve_addresses_numeric = GNUNET_NO;
972   opt_monitor = GNUNET_NO;
973   opt_list_all = GNUNET_NO;
974   opt_list_used = GNUNET_NO;
975   opt_set_pref = GNUNET_NO;
976   stat_pending = 0;
977   stat_receive_done = GNUNET_NO;
978   opt_type_str = NULL;
979
980   static const struct GNUNET_GETOPT_CommandLineOption options[] =
981   {
982   { 'u', "used", NULL,
983       gettext_noop ("get list of active addresses currently used"), 0,
984       &GNUNET_GETOPT_set_one, &opt_list_used },
985   { 'a', "all", NULL, gettext_noop ("get list of all active addresses"), 0,
986       &GNUNET_GETOPT_set_one, &opt_list_all },
987   { 'n', "numeric", NULL,
988       gettext_noop ("do not resolve IP addresses to hostnames"), 0,
989       &GNUNET_GETOPT_set_one, &opt_resolve_addresses_numeric },
990   { 'm', "monitor", NULL, gettext_noop ("monitor mode"), 0,
991       &GNUNET_GETOPT_set_one, &opt_monitor },
992   { 'p', "preference", NULL, gettext_noop ("set preference for the given peer"),
993       0, &GNUNET_GETOPT_set_one, &opt_set_pref },
994   { 'q', "quotas", NULL, gettext_noop ("print all configured quotas"), 0,
995       &GNUNET_GETOPT_set_one, &opt_print_quotas },
996   { 'i', "id", "TYPE", gettext_noop ("peer id"), 1, &GNUNET_GETOPT_set_string,
997       &opt_pid_str },
998   { 't', "type", "TYPE",
999       gettext_noop ("preference type to set: latency | bandwidth"), 1,
1000       &GNUNET_GETOPT_set_string, &opt_type_str },
1001   { 'k', "value", "VALUE", gettext_noop ("preference value"), 1,
1002       &GNUNET_GETOPT_set_uint, &opt_pref_value },
1003   { 'V', "verbose", NULL,
1004       gettext_noop ("verbose output (include ATS address properties)"), 0,
1005       &GNUNET_GETOPT_set_one, &opt_verbose }, GNUNET_GETOPT_OPTION_END };
1006
1007   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1008     return 2;
1009
1010   res = GNUNET_PROGRAM_run (argc, argv, "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
1025 /* end of gnunet-ats.c */