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