- switch to netstat for compatiblity
[oweals/gnunet.git] / src / integration-tests / connection_watchdog.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 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  * @file integration-tests/connection_watchdog.c
22  * @brief tool to monitor core and transport connections for consistency
23  * @author Matthias Wachs
24  */
25 #include "platform.h"
26 #include "gnunet_common.h"
27 #include "gnunet_constants.h"
28 #include "gnunet_arm_service.h"
29 #include "gnunet_core_service.h"
30 #include "gnunet_getopt_lib.h"
31 #include "gnunet_os_lib.h"
32 #include "gnunet_program_lib.h"
33 #include "gnunet_scheduler_lib.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_statistics_service.h"
36
37
38 #define CHECK_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
39 #define STATS_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
40 #define REPEATED_STATS_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
41 #define STATS_VALUES 4
42
43 /**
44  * Final status code.
45  */
46 static int ret;
47
48 static int have_tcp;
49 static int have_udp;
50 static int have_http;
51 static int have_https;
52 static int have_unix;
53
54 static struct GNUNET_TRANSPORT_Handle *th;
55 static struct GNUNET_CORE_Handle *ch;
56 static struct GNUNET_PeerIdentity my_peer_id;
57 static const struct GNUNET_CONFIGURATION_Handle *mycfg;
58 static struct GNUNET_STATISTICS_Handle *stats;
59
60
61 static unsigned int transport_connections;
62 static unsigned int core_connections;
63
64 static GNUNET_SCHEDULER_TaskIdentifier check_task;
65 static GNUNET_SCHEDULER_TaskIdentifier statistics_task;
66
67 static uint64_t statistics_transport_connections;
68 static uint64_t statistics_transport_tcp_connections;
69 static uint64_t statistics_core_neighbour_entries;
70 static uint64_t statistics_core_entries_session_map;
71
72 int stat_check_running;
73
74 static struct GNUNET_CONTAINER_MultiHashMap *peers;
75
76 struct PeerContainer
77 {
78   struct GNUNET_PeerIdentity id;
79   int transport_connected;
80   int core_connected;
81 };
82
83
84 enum protocol
85 {
86   tcp,
87   udp,
88   unixdomain
89 };
90
91 struct TransportPlugin
92 {
93   /**
94    * This is a doubly-linked list.
95    */
96   struct TransportPlugin *next;
97
98   /**
99    * This is a doubly-linked list.
100    */
101   struct TransportPlugin *prev;
102
103   /**
104    * Short name for the plugin (i.e. "tcp").
105    */
106   char *short_name;
107
108   int port;
109
110   int protocol;
111 };
112
113 struct TransportPlugin *phead;
114 struct TransportPlugin *ptail;
115
116 int map_check_it (void *cls,
117                   const GNUNET_HashCode * key,
118                   void *value)
119 {
120   int *fail = cls;
121   struct PeerContainer *pc = value;
122   if (pc->core_connected != pc->transport_connected)
123   {
124     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
125      "Inconsistend peer `%s': TRANSPORT %s <-> CORE %s\n",
126      GNUNET_i2s (&pc->id),
127      (GNUNET_YES == pc->transport_connected) ? "YES" : "NO",
128      (GNUNET_YES == pc->core_connected) ? "YES" : "NO");
129     (*fail) ++;
130   }
131
132   return GNUNET_OK;
133 }
134
135
136 int map_cleanup_it (void *cls,
137                   const GNUNET_HashCode * key,
138                   void *value)
139 {
140   struct PeerContainer *pc = value;
141   GNUNET_CONTAINER_multihashmap_remove(peers, key, value);
142   GNUNET_free (pc);
143   return GNUNET_OK;
144 }
145
146 static void
147 map_cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
148 {
149   GNUNET_CONTAINER_multihashmap_iterate (peers, &map_cleanup_it, NULL);
150   GNUNET_CONTAINER_multihashmap_destroy(peers);
151 }
152
153 static void
154 map_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
155 {
156   int fail = 0;
157   check_task = GNUNET_SCHEDULER_NO_TASK;
158   GNUNET_CONTAINER_multihashmap_iterate (peers, &map_check_it, &fail);
159   if (0 > fail)
160     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
161        "Inconsistent peers after connection consistency check: %u\n", fail);
162   else
163     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
164        "Inconsistent peers after connection consistency check: %u\n", fail);
165
166
167   if (NULL != cls)
168   {
169     GNUNET_SCHEDULER_add_now (cls, NULL);
170   }
171 }
172
173
174 static void
175 stats_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
176
177 static int
178 check_lowlevel_connections (int port, int protocol)
179 {
180   FILE *f;
181   char * cmdline;
182   char * proto;
183   char line[1024];
184   int count = -1;
185 #ifdef MINGW
186   /* not supported */
187   return count;
188 #else
189
190   switch (protocol) {
191     case tcp:
192       proto = "-t";
193       break;
194     case udp:
195       proto = "-u";
196       break;
197     case unixdomain:
198       proto = "-x";
199       break;
200     default:
201       proto = "";
202       break;
203   }
204
205
206   GNUNET_asprintf(&cmdline, "netstat -n %s | grep %u", proto, port);
207
208   if (system ("netstat -n > /dev/null 2> /dev/null"))
209     if (system ("netstat -n > /dev/null 2> /dev/null") == 0)
210       f = popen (cmdline, "r");
211     else
212       f = NULL;
213   else
214     f = popen (cmdline, "r");
215   if (!f)
216   {
217     GNUNET_log_strerror(GNUNET_ERROR_TYPE_ERROR, "ss");
218     GNUNET_free (cmdline);
219     return -1;
220   }
221
222   count = 0;
223   while (NULL != fgets (line, sizeof (line), f))
224   {
225     /* read */
226     //printf ("%s", line);
227     count ++;
228   }
229
230   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%i TCP connections established with port %u\n",
231        count, port);
232
233   pclose (f);
234   GNUNET_free (cmdline);
235   return count;
236 #endif
237 }
238
239
240 static struct TransportPlugin *
241 find_plugin (char * name)
242 {
243   struct TransportPlugin *cur = NULL;
244
245   for (cur = phead; cur != NULL; cur = phead)
246   {
247     if (0 == strcmp(name, cur->short_name))
248       return cur;
249   }
250   return cur;
251 }
252
253 int stats_check_cb (void *cls, const char *subsystem,
254                    const char *name, uint64_t value,
255                    int is_persistent)
256 {
257   static int counter;
258
259   uint64_t *val = cls;
260
261   if (NULL != val)
262     (*val) = value;
263
264   counter ++;
265   if ((STATS_VALUES == counter) || ((GNUNET_NO == have_tcp) && (STATS_VALUES - 1 == counter)))
266   {
267     int fail = GNUNET_NO;
268
269
270
271     int low_level_connections_udp = check_lowlevel_connections (2086, udp);
272
273     if (transport_connections != core_connections)
274     {
275       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
276            "%u transport notifications <-> %u core notifications\n",
277            transport_connections, core_connections);
278       fail = GNUNET_YES;
279     }
280
281     if (transport_connections != statistics_transport_connections)
282     {
283       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
284            "%u transport notifications <-> %u in statistics (peers connected)\n",
285            transport_connections, statistics_transport_connections);
286       fail = GNUNET_YES;
287     }
288
289     if (core_connections != statistics_core_entries_session_map)
290     {
291       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
292            "%u core notifications <-> %u in statistics (entries session map)\n",
293            core_connections, statistics_core_entries_session_map);
294       fail = GNUNET_YES;
295     }
296
297     if (core_connections != statistics_core_neighbour_entries)
298     {
299       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
300            "%u core notifications <-> %u in statistics (neighbour entries allocated)\n",
301            core_connections, statistics_core_neighbour_entries);
302       fail = GNUNET_YES;
303     }
304
305     if (GNUNET_NO == fail)
306       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
307          "Check successful : (%u transport / %u core) connections established\n", transport_connections, core_connections);
308
309     /* TCP plugin specific checks */
310     if (GNUNET_YES == have_tcp)
311     {
312       struct TransportPlugin * p = find_plugin ("tcp");
313       int low_level_connections_tcp = check_lowlevel_connections (p->port, p->protocol);
314
315       if (low_level_connections_tcp != -1)
316       {
317         if (statistics_transport_tcp_connections > low_level_connections_tcp)
318         {
319           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
320                "%u transport tcp sessions <-> %i established tcp connections\n",
321                statistics_transport_tcp_connections, low_level_connections_tcp);
322           fail = GNUNET_YES;
323         }
324         else if (low_level_connections_tcp != -1)
325         {
326           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
327                "%u TCP connections, %u UDP connections \n",
328                low_level_connections_tcp, low_level_connections_udp);
329         }
330       }
331       if (transport_connections > statistics_transport_tcp_connections)
332       {
333         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
334              "%u transport notifications <-> %u in statistics (statistics_transport_tcp_connections)\n",
335              transport_connections, statistics_transport_tcp_connections);
336         fail = GNUNET_YES;
337       }
338       else
339       {
340         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
341              " %u transport notifications <-> %u in statistics (statistics_transport_tcp_connections)\n",
342              transport_connections, statistics_transport_tcp_connections);
343       }
344     }
345
346     if (GNUNET_SCHEDULER_NO_TASK == statistics_task)
347       statistics_task = GNUNET_SCHEDULER_add_delayed(REPEATED_STATS_DELAY, &stats_check, NULL);
348
349     stat_check_running = GNUNET_NO;
350     counter = 0;
351   }
352
353   return GNUNET_OK;
354 }
355
356
357 static void
358 stats_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
359 {
360   statistics_task = GNUNET_SCHEDULER_NO_TASK;
361
362   if (GNUNET_YES == stat_check_running)
363   {
364     statistics_task = GNUNET_SCHEDULER_add_delayed(STATS_DELAY, &stats_check, NULL);
365   }
366
367   stat_check_running = GNUNET_YES;
368
369   statistics_transport_connections = 0 ;
370   statistics_core_entries_session_map = 0;
371   statistics_core_neighbour_entries = 0;
372
373   GNUNET_STATISTICS_get (stats, "transport", "# peers connected", GNUNET_TIME_UNIT_MINUTES, NULL, &stats_check_cb, &statistics_transport_connections);
374   GNUNET_STATISTICS_get (stats, "core", "# neighbour entries allocated", GNUNET_TIME_UNIT_MINUTES, NULL, &stats_check_cb, &statistics_core_neighbour_entries);
375   GNUNET_STATISTICS_get (stats, "core", "# entries in session map", GNUNET_TIME_UNIT_MINUTES, NULL, &stats_check_cb, &statistics_core_entries_session_map);
376
377   /* TCP plugin specific checks */
378   if (GNUNET_YES == have_tcp)
379     GNUNET_STATISTICS_get (stats, "transport", "# TCP sessions active", GNUNET_TIME_UNIT_MINUTES, NULL, &stats_check_cb, &statistics_transport_tcp_connections);
380
381
382 }
383
384
385 static void
386 map_connect (const struct GNUNET_PeerIdentity *peer, void * source)
387 {
388   struct PeerContainer * pc;
389   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(peers, &peer->hashPubKey))
390   {
391     pc = GNUNET_malloc (sizeof (struct PeerContainer));
392     pc->id = *peer;
393     pc->core_connected = GNUNET_NO;
394     pc->transport_connected = GNUNET_NO;
395     GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(peers, &peer->hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
396   }
397
398   pc = GNUNET_CONTAINER_multihashmap_get(peers, &peer->hashPubKey);
399   if (source == th)
400   {
401     if (GNUNET_NO == pc->transport_connected)
402     {
403       pc->transport_connected = GNUNET_YES;
404     }
405     else
406     {
407       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
408            "%s notified multiple times about for peers `%s' (%s : %s)\n",
409            "TRANSPORT",
410            GNUNET_i2s (&pc->id),
411            "CORE", (pc->core_connected == GNUNET_YES) ? "yes" : "no");
412       GNUNET_break (0);
413     }
414   }
415   if (source == ch)
416   {
417     if (GNUNET_NO == pc->core_connected)
418     {
419       pc->core_connected = GNUNET_YES;
420     }
421     else
422     {
423       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
424            "%s notified multiple times about for peers `%s' (%s : %s)\n",
425            "CORE",
426            GNUNET_i2s (&pc->id),
427                "TRANSPORT", (pc->transport_connected == GNUNET_YES) ? "yes" : "no");
428       GNUNET_break (0);
429     }
430   }
431   if (GNUNET_SCHEDULER_NO_TASK != check_task)
432     GNUNET_SCHEDULER_cancel(check_task);
433   check_task = GNUNET_SCHEDULER_add_delayed(CHECK_DELAY, &map_check, NULL);
434
435   if (GNUNET_SCHEDULER_NO_TASK != statistics_task)
436     GNUNET_SCHEDULER_cancel(statistics_task);
437   statistics_task = GNUNET_SCHEDULER_add_delayed(STATS_DELAY, &stats_check, NULL);
438 }
439
440
441 static void
442 map_disconnect (const struct GNUNET_PeerIdentity * peer, void * source)
443 {
444
445   struct PeerContainer * pc;
446   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(peers, &peer->hashPubKey))
447   {
448     if (source == th)
449     {
450       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
451          "%s disconnect notification for unknown peer `%s'\n",
452          "TRANSPORT", GNUNET_i2s (peer));
453       GNUNET_break (0);
454       return;
455     }
456     if (source == ch)
457     {
458       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
459          "%s disconnect notification for unknown peer `%s'\n",
460          "CORE", GNUNET_i2s (peer));
461       return;
462     }
463   }
464
465   pc = GNUNET_CONTAINER_multihashmap_get(peers, &peer->hashPubKey);
466   if (source == th)
467   {
468     if (GNUNET_YES == pc->transport_connected)
469     {
470       pc->transport_connected = GNUNET_NO;
471     }
472     else
473     {
474       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
475            "%s notified for not connected peer `%s' (%s : %s)\n",
476            "TRANSPORT",
477            GNUNET_i2s (&pc->id),
478            "CORE", (pc->core_connected == GNUNET_YES) ? "yes" : "no");
479       GNUNET_break (0);
480     }
481   }
482   if (source == ch)
483   {
484     if (GNUNET_YES == pc->core_connected)
485     {
486       pc->core_connected = GNUNET_NO;
487     }
488     else
489     {
490       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
491            "%s notified for not connected peer `%s' (%s : %s)\n",
492            "CORE",
493            GNUNET_i2s (&pc->id),
494            "TRANSPORT", (pc->transport_connected == GNUNET_YES) ? "yes" : "no");
495       GNUNET_break (0);
496     }
497   }
498
499   if ((GNUNET_NO == pc->core_connected) && (GNUNET_NO == pc->transport_connected))
500   {
501     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing peer `%s'\n", GNUNET_i2s (&pc->id));
502     GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (peers, &peer->hashPubKey, pc));
503     GNUNET_free (pc);
504   }
505
506   if (GNUNET_SCHEDULER_NO_TASK != check_task)
507     GNUNET_SCHEDULER_cancel(check_task);
508   check_task = GNUNET_SCHEDULER_add_delayed(CHECK_DELAY, &map_check, NULL);
509
510   if (GNUNET_SCHEDULER_NO_TASK != statistics_task)
511     GNUNET_SCHEDULER_cancel(statistics_task);
512   statistics_task = GNUNET_SCHEDULER_add_delayed(STATS_DELAY, &stats_check, NULL);
513 }
514
515
516 static void
517 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
518 {
519   struct TransportPlugin * cur = phead;
520
521   if (NULL != th)
522   {
523     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disconnecting from transport service\n");
524     GNUNET_TRANSPORT_disconnect (th);
525     th = NULL;
526   }
527   if (NULL != ch)
528   {
529     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disconnecting from core service\n");
530     GNUNET_CORE_disconnect (ch);
531     ch = NULL;
532   }
533
534   if (GNUNET_SCHEDULER_NO_TASK != statistics_task)
535   {
536     GNUNET_SCHEDULER_cancel(statistics_task);
537     statistics_task = GNUNET_SCHEDULER_NO_TASK;
538   }
539
540   if (GNUNET_SCHEDULER_NO_TASK != check_task)
541   {
542     GNUNET_SCHEDULER_cancel(check_task);
543     check_task = GNUNET_SCHEDULER_NO_TASK;
544   }
545
546   for (cur = phead; cur != NULL; cur = phead)
547   {
548     GNUNET_CONTAINER_DLL_remove(phead, ptail, cur);
549     GNUNET_free (cur->short_name);
550     GNUNET_free (cur);
551   }
552
553   check_task = GNUNET_SCHEDULER_add_now (&map_check, &map_cleanup);
554 }
555
556 void
557 transport_notify_connect_cb (void *cls,
558                 const struct GNUNET_PeerIdentity
559                 * peer,
560                 const struct
561                 GNUNET_ATS_Information * ats,
562                 uint32_t ats_count)
563 {
564   transport_connections ++;
565   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "TRANSPORT connect for peer `%s' (%u total)\n",
566       GNUNET_i2s (peer), transport_connections);
567   map_connect (peer, th);
568 }
569
570 /**
571  * Function called to notify transport users that another
572  * peer disconnected from us.
573  *
574  * @param cls closure
575  * @param peer the peer that disconnected
576  */
577 void
578 transport_notify_disconnect_cb (void *cls,
579                                const struct
580                                GNUNET_PeerIdentity * peer)
581 {
582   GNUNET_assert (transport_connections > 0);
583   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "TRANSPORT disconnect for peer `%s' (%u total)\n",
584       GNUNET_i2s (peer), transport_connections) ;
585   map_disconnect (peer, th);
586   transport_connections --;
587
588 }
589
590
591 static void
592 core_connect_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
593                       const struct GNUNET_ATS_Information *atsi,
594                       unsigned int atsi_count)
595 {
596   if (0 != memcmp (peer, &my_peer_id, sizeof (struct GNUNET_PeerIdentity)))
597   {
598     core_connections ++;
599     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CORE      connect for peer `%s' (%u total)\n",
600       GNUNET_i2s (peer), core_connections);
601     map_connect (peer, ch);
602   }
603   else
604   {
605     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CORE      connect for myself `%s' (%u total)\n",
606       GNUNET_i2s (peer), core_connections);
607   }
608 }
609
610 static void
611 core_disconnect_cb (void *cls,
612                       const struct
613                       GNUNET_PeerIdentity * peer)
614 {
615   if (0 != memcmp (peer, &my_peer_id, sizeof (struct GNUNET_PeerIdentity)))
616   {
617     GNUNET_assert (core_connections >= 0);
618     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CORE      disconnect for peer `%s' (%u total)\n",
619       GNUNET_i2s (peer), core_connections);
620     map_disconnect (peer, ch);
621     core_connections --;
622   }
623   else
624   {
625     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CORE      disconnect for myself `%s' (%u total)\n",
626       GNUNET_i2s (peer), core_connections);
627   }
628
629 }
630
631 static void
632 core_init_cb (void *cls, struct GNUNET_CORE_Handle *server,
633                    const struct GNUNET_PeerIdentity *my_identity)
634 {
635   my_peer_id = *my_identity;
636   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to core service\n");
637 }
638
639
640 static void
641 init ()
642 {
643   struct TransportPlugin * cur;
644   char *plugs;
645   char *pos;
646   char *secname;
647   int counter;
648   long long unsigned int port;
649
650   have_tcp = GNUNET_NO;
651   have_udp = GNUNET_NO;
652   have_http = GNUNET_NO;
653   have_https = GNUNET_NO;
654   have_unix = GNUNET_NO;
655
656   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (mycfg, "TRANSPORT", "PLUGINS", &plugs))
657     return;
658   counter = 0;
659   for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
660   {
661     counter++;
662
663     GNUNET_asprintf(&secname, "transport-%s", pos);
664
665     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (mycfg, secname, "PORT", &port))
666     {
667       GNUNET_free (secname);
668       continue;
669     }
670
671     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport plugin: `%s' port %llu\n"), pos, port);
672     cur = GNUNET_malloc(sizeof (struct TransportPlugin));
673     cur->short_name = strdup (pos);
674     cur->port = port;
675     if (0 == strcmp("tcp", pos))
676     {
677       have_tcp = GNUNET_YES;
678       cur->protocol = tcp;
679     }
680     if (0 == strcmp("udp", pos))
681     {
682       have_udp = GNUNET_YES;
683       cur->protocol = udp;
684     }
685     if (0 == strcmp("http", pos))
686     {
687       have_http = GNUNET_YES;
688       cur->protocol = tcp;
689     }
690     if (0 == strcmp("https", pos))
691     {
692       have_https = GNUNET_YES;
693       cur->protocol = tcp;
694     }
695     if (0 == strcmp("unix", pos))
696     {
697       have_unix = GNUNET_YES;
698       cur->protocol = unixdomain;
699     }
700
701     GNUNET_CONTAINER_DLL_insert(phead, ptail, cur);
702     GNUNET_free (secname);
703   }
704   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Found %u transport plugins: `%s'\n"),
705               counter, plugs);
706
707   GNUNET_free (plugs);
708 }
709
710 /**
711  * Main function that will be run by the scheduler.
712  *
713  * @param cls closure
714  * @param args remaining command-line arguments
715  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
716  * @param cfg configuration
717  */
718 static void
719 run (void *cls, char *const *args, const char *cfgfile,
720      const struct GNUNET_CONFIGURATION_Handle *cfg)
721 {
722   transport_connections = 0;
723   core_connections = 0;
724   mycfg = cfg;
725
726   init();
727
728   stats = GNUNET_STATISTICS_create ("watchdog", cfg);
729   peers = GNUNET_CONTAINER_multihashmap_create (20);
730
731   th = GNUNET_TRANSPORT_connect(cfg, NULL, NULL, NULL,
732                                 &transport_notify_connect_cb,
733                                 &transport_notify_disconnect_cb);
734   GNUNET_assert (th != NULL);
735   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to transport service\n");
736   ch =  GNUNET_CORE_connect (cfg, 1, NULL,
737                              &core_init_cb,
738                              &core_connect_cb,
739                              &core_disconnect_cb,
740                              NULL, GNUNET_NO,
741                              NULL, GNUNET_NO,
742                              NULL);
743   GNUNET_assert (ch != NULL);
744
745   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, NULL);
746
747 }
748
749
750 /**
751  * The main function.
752  *
753  * @param argc number of arguments from the command line
754  * @param argv command line arguments
755  * @return 0 ok, 1 on error
756  */
757 int
758 main (int argc, char *const *argv)
759 {
760   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
761     /* FIMXE: add options here */
762     GNUNET_GETOPT_OPTION_END
763   };
764   return (GNUNET_OK ==
765           GNUNET_PROGRAM_run (argc, argv, "cn",
766                               gettext_noop ("help text"), options, &run,
767                               NULL)) ? ret : 1;
768 }
769
770 /* end of connection_watchdog.c */