indentation
[oweals/gnunet.git] / src / chat / test_chat_private.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 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 chat/test_chat_private.c
23  * @brief testcase for private chatting
24  * @author Vitaly Minko
25  */
26
27 #include "platform.h"
28 #include "gnunet_crypto_lib.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_arm_service.h"
31 #include "gnunet_chat_service.h"
32
33 #define VERBOSE GNUNET_NO
34
35 #define START_ARM GNUNET_YES
36
37 /**
38  * How long until we give up on passing the test?
39  */
40 #define KILL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
41
42 /**
43  * How long until we give up on receiving somebody else's private message?
44  */
45 #define PM_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
46
47 struct PeerContext
48 {
49   struct GNUNET_CONFIGURATION_Handle *cfg;
50 #if START_ARM
51   struct GNUNET_OS_Process *arm_proc;
52 #endif
53 };
54
55 struct Wanted
56 {
57   struct GNUNET_CONTAINER_MetaData *meta;
58
59   GNUNET_HashCode *sender;
60
61   /**
62    * Alternative meta/sender is used when we expect join/leave notification
63    * from two peers and don't know which one will come first.
64    */
65   struct GNUNET_CONTAINER_MetaData *meta2;
66
67   GNUNET_HashCode *sender2;
68
69   char *msg;
70
71   const char *me;
72
73   enum GNUNET_CHAT_MsgOptions opt;
74
75   struct GNUNET_TIME_Absolute timestamp;
76
77   GNUNET_SCHEDULER_Task next_task;
78
79   void *next_task_cls;
80
81 };
82
83 static struct PeerContext p1;
84
85 static struct PeerContext p2;
86
87 static struct PeerContext p3;
88
89 static GNUNET_HashCode alice;
90
91 static GNUNET_HashCode bob;
92
93 static GNUNET_HashCode carol;
94
95 static struct GNUNET_CHAT_Room *alice_room;
96
97 static struct GNUNET_CHAT_Room *bob_room;
98
99 static struct GNUNET_CHAT_Room *carol_room;
100
101 static struct GNUNET_CONTAINER_MetaData *alice_meta;
102
103 static struct GNUNET_CONTAINER_MetaData *bob_meta;
104
105 static struct GNUNET_CONTAINER_MetaData *carol_meta;
106
107 static struct Wanted alice_wanted;
108
109 static struct Wanted bob_wanted;
110
111 static struct Wanted carol_wanted;
112
113 static GNUNET_SCHEDULER_TaskIdentifier kill_task;
114
115 static GNUNET_SCHEDULER_TaskIdentifier finish_task;
116
117 static GNUNET_SCHEDULER_TaskIdentifier wait_task;
118
119 static int err;
120
121 static int alice_ready;
122
123 static int bob_ready;
124
125 static int is_p2p;
126
127 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *bob_public_key = NULL;
128
129
130 static void
131 setup_peer (struct PeerContext *p, const char *cfgname)
132 {
133   p->cfg = GNUNET_CONFIGURATION_create ();
134 #if START_ARM
135   p->arm_proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
136                                          "gnunet-service-arm",
137 #if VERBOSE
138                                          "-L", "DEBUG",
139 #endif
140                                          "-c", cfgname, NULL);
141 #endif
142   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
143 }
144
145
146 static void
147 stop_arm (struct PeerContext *p)
148 {
149 #if START_ARM
150   if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
151     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
152   if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK)
153     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
154   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
155               "ARM process %u stopped\n",
156               GNUNET_OS_process_get_pid (p->arm_proc));
157   GNUNET_OS_process_close (p->arm_proc);
158   p->arm_proc = NULL;
159 #endif
160   GNUNET_CONFIGURATION_destroy (p->cfg);
161 }
162
163
164 static void
165 abort_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
166 {
167   if (alice_room != NULL)
168   {
169     GNUNET_CHAT_leave_room (alice_room);
170     alice_room = NULL;
171   }
172   if (bob_room != NULL)
173   {
174     GNUNET_CHAT_leave_room (bob_room);
175     bob_room = NULL;
176   }
177   if (carol_room != NULL)
178   {
179     GNUNET_CHAT_leave_room (carol_room);
180     carol_room = NULL;
181   }
182   err = 1;
183 }
184
185
186 static void
187 timeout_kill (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
188 {
189 #if VERBOSE
190   printf ("Timed out, stopping the test.\n");
191 #endif
192   kill_task = GNUNET_SCHEDULER_NO_TASK;
193   if (wait_task != GNUNET_SCHEDULER_NO_TASK)
194   {
195     GNUNET_SCHEDULER_cancel (wait_task);
196     wait_task = GNUNET_SCHEDULER_NO_TASK;
197   }
198   GNUNET_SCHEDULER_add_continuation (&abort_test, NULL,
199                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
200 }
201
202
203 static int
204 join_cb (void *cls)
205 {
206   struct Wanted *want = cls;
207
208 #if VERBOSE
209   printf ("%s has joined\n", want->me);
210 #endif
211   if (NULL != want->next_task)
212     GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls);
213   return GNUNET_OK;
214 }
215
216
217 static int
218 member_list_cb (void *cls,
219                 const struct GNUNET_CONTAINER_MetaData *member_info,
220                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *member_id,
221                 enum GNUNET_CHAT_MsgOptions options)
222 {
223   struct Wanted *want = cls;
224   GNUNET_HashCode sender;
225
226 #if VERBOSE
227   printf ("%s - told that %s has %s\n",
228           want->me,
229           member_info == NULL ? NULL
230           : GNUNET_CONTAINER_meta_data_get_by_type (member_info,
231                                                     EXTRACTOR_METATYPE_TITLE),
232           member_info == NULL ? "left" : "joined");
233 #endif
234   GNUNET_CRYPTO_hash (member_id,
235                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
236                       &sender);
237   /* entertain both primary and an alternative sender/meta */
238   if (((0 == memcmp (&sender, want->sender, sizeof (GNUNET_HashCode))) ||
239        ((want->sender2 != NULL) &&
240         (0 == memcmp (&sender, want->sender2, sizeof (GNUNET_HashCode))))) &&
241       (((member_info == NULL) && (want->meta == NULL)) ||
242        ((member_info != NULL) &&
243         (((want->meta != NULL) &&
244           GNUNET_CONTAINER_meta_data_test_equal (member_info,
245                                                  want->meta)) ||
246          ((want->meta2 != NULL) &&
247           GNUNET_CONTAINER_meta_data_test_equal (member_info,
248                                                  want->meta2))))) &&
249       (options == want->opt))
250   {
251     /* remember Bob's public key, we need it to send private message */
252     if (NULL == bob_public_key &&
253         (0 == memcmp (&bob, want->sender, sizeof (GNUNET_HashCode))))
254       bob_public_key =
255           GNUNET_memdup (member_id,
256                          sizeof (struct
257                                  GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
258     if (want->sender2 != NULL)
259     {
260       /* flush alternative sender */
261       if (0 == memcmp (&sender, want->sender, sizeof (GNUNET_HashCode)))
262       {
263         want->sender = want->sender2;
264         want->meta = want->meta2;
265       }
266       want->sender2 = NULL;
267       want->meta2 = NULL;
268     }
269     else if (NULL != want->next_task)
270       GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls);
271   }
272   else
273   {
274     GNUNET_SCHEDULER_cancel (kill_task);
275     kill_task = GNUNET_SCHEDULER_NO_TASK;
276     GNUNET_SCHEDULER_add_now (&abort_test, NULL);
277   }
278   return GNUNET_OK;
279 }
280
281
282 static int
283 receive_cb (void *cls,
284             struct GNUNET_CHAT_Room *room,
285             const GNUNET_HashCode * sender,
286             const struct GNUNET_CONTAINER_MetaData *meta,
287             const char *message,
288             struct GNUNET_TIME_Absolute timestamp,
289             enum GNUNET_CHAT_MsgOptions options)
290 {
291   struct Wanted *want = cls;
292
293 #if VERBOSE
294   printf ("%s - told that %s said '%s'\n",
295           want->me,
296           meta == NULL ? NULL
297           : GNUNET_CONTAINER_meta_data_get_by_type (meta,
298                                                     EXTRACTOR_METATYPE_TITLE),
299           message);
300 #endif
301
302   if ((want->msg != NULL) && (0 == strcmp (message, want->msg)) &&
303       (((sender == NULL) && (want->sender == NULL)) ||
304        ((sender != NULL) && (want->sender != NULL) &&
305         (0 == memcmp (sender, want->sender,
306                       sizeof (GNUNET_HashCode))))) &&
307       (GNUNET_CONTAINER_meta_data_test_equal (meta, want->meta)) &&
308       (options == want->opt) &&
309       /* Not == since the library sets the actual timestamp, so it may be
310        * slightly greater
311        */
312       (timestamp.abs_value >= want->timestamp.abs_value))
313   {
314     if (NULL != want->next_task)
315       GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls);
316   }
317   else
318   {
319     GNUNET_SCHEDULER_cancel (kill_task);
320     kill_task = GNUNET_SCHEDULER_NO_TASK;
321     GNUNET_SCHEDULER_cancel (finish_task);
322     finish_task = GNUNET_SCHEDULER_NO_TASK;
323     GNUNET_SCHEDULER_add_now (&abort_test, NULL);
324   }
325   return GNUNET_OK;
326 }
327
328
329 static void
330 wait_until_all_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
331 {
332   GNUNET_SCHEDULER_Task task = cls;
333
334 #if VERBOSE
335   printf ("Waiting...\n");
336 #endif
337   if (alice_ready && bob_ready)
338   {
339     wait_task = GNUNET_SCHEDULER_NO_TASK;
340     GNUNET_SCHEDULER_add_now (task, NULL);
341   }
342   else
343     wait_task =
344         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
345                                       (GNUNET_TIME_UNIT_MILLISECONDS, 5000),
346                                       &wait_until_all_ready, task);
347 }
348
349
350 static void
351 set_alice_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
352 {
353   alice_ready = GNUNET_YES;
354 }
355
356
357 static void
358 set_bob_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
359 {
360   bob_ready = GNUNET_YES;
361 }
362
363
364 static void
365 disconnect_alice (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
366 {
367 #if VERBOSE
368   printf ("Alice is leaving.\n");
369 #endif
370   if (is_p2p)
371     stop_arm (&p2);
372   GNUNET_CHAT_leave_room (alice_room);
373   alice_room = NULL;
374   GNUNET_SCHEDULER_cancel (kill_task);
375   kill_task = GNUNET_SCHEDULER_NO_TASK;
376 }
377
378
379 static void
380 disconnect_bob (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
381 {
382 #if VERBOSE
383   printf ("Bod is leaving.\n");
384 #endif
385   if (is_p2p)
386     stop_arm (&p3);
387   alice_wanted.meta = NULL;
388   alice_wanted.sender = &bob;
389   alice_wanted.msg = NULL;
390   alice_wanted.opt = 0;
391   alice_wanted.next_task = &disconnect_alice;
392   alice_wanted.next_task_cls = NULL;
393   GNUNET_CHAT_leave_room (bob_room);
394   bob_room = NULL;
395 }
396
397
398 static void
399 disconnect_carol (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
400 {
401 #if VERBOSE
402   printf ("Carol is leaving.\n");
403 #endif
404   alice_wanted.meta = NULL;
405   alice_wanted.sender = &carol;
406   alice_wanted.msg = NULL;
407   alice_wanted.opt = 0;
408   alice_wanted.next_task = &set_alice_ready;
409   alice_wanted.next_task_cls = NULL;
410   alice_ready = GNUNET_NO;
411   bob_wanted.meta = NULL;
412   bob_wanted.sender = &carol;
413   bob_wanted.msg = NULL;
414   bob_wanted.opt = 0;
415   bob_wanted.next_task = &wait_until_all_ready;
416   bob_wanted.next_task_cls = &disconnect_bob;
417   bob_ready = GNUNET_YES;
418   GNUNET_CHAT_leave_room (carol_room);
419   carol_room = NULL;
420 }
421
422
423 static void
424 send_from_alice_to_bob (void *cls,
425                         const struct GNUNET_SCHEDULER_TaskContext *tc)
426 {
427   uint32_t seq;
428
429 #if VERBOSE
430   printf ("Alice says 'Hi!' to Bob\n");
431 #endif
432   alice_ready = GNUNET_YES;
433   bob_ready = GNUNET_NO;
434   bob_wanted.meta = alice_meta;
435   bob_wanted.sender = &alice;
436   bob_wanted.msg = "Hi Bob!";
437   bob_wanted.opt = GNUNET_CHAT_MSG_PRIVATE;
438   bob_wanted.next_task = &set_bob_ready;
439   bob_wanted.next_task_cls = NULL;
440   /* Carol should not receive this message */
441   carol_wanted.meta = NULL;
442   carol_wanted.sender = NULL;
443   carol_wanted.msg = NULL;
444   carol_wanted.opt = 0;
445   carol_wanted.next_task = NULL;
446   carol_wanted.next_task_cls = NULL;
447   GNUNET_CHAT_send_message (alice_room,
448                             "Hi Bob!",
449                             GNUNET_CHAT_MSG_PRIVATE, bob_public_key, &seq);
450   finish_task = GNUNET_SCHEDULER_add_delayed (PM_TIMEOUT,
451                                               &wait_until_all_ready,
452                                               &disconnect_carol);
453 }
454
455
456 static void
457 prepare_bob_for_alice_task (void *cls,
458                             const struct GNUNET_SCHEDULER_TaskContext *tc)
459 {
460   bob_wanted.meta = alice_meta;
461   bob_wanted.sender = &alice;
462   bob_wanted.msg = NULL;
463   bob_wanted.opt = -1;
464   bob_wanted.next_task = &set_bob_ready;
465   bob_wanted.next_task_cls = NULL;
466 }
467
468
469 static void
470 prepare_carol_for_alice_and_bob_task (void *cls,
471                                       const struct GNUNET_SCHEDULER_TaskContext
472                                       *tc)
473 {
474   carol_wanted.meta = alice_meta;
475   carol_wanted.sender = &alice;
476   /* set alternative meta/sender since we don't know from which peer
477    * notification will come first */
478   carol_wanted.meta2 = bob_meta;
479   carol_wanted.sender2 = &bob;
480   carol_wanted.msg = NULL;
481   carol_wanted.opt = -1;
482   carol_wanted.next_task = &wait_until_all_ready;
483   carol_wanted.next_task_cls = &send_from_alice_to_bob;
484 }
485
486
487 static void
488 join_carol_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
489 {
490 #if VERBOSE
491   printf ("Carol joining\n");
492 #endif
493   alice_wanted.meta = carol_meta;
494   alice_wanted.sender = &carol;
495   alice_wanted.msg = NULL;
496   alice_wanted.opt = -1;
497   alice_wanted.next_task = &set_alice_ready;
498   alice_wanted.next_task_cls = NULL;
499   alice_ready = GNUNET_NO;
500   bob_wanted.meta = carol_meta;
501   bob_wanted.sender = &carol;
502   bob_wanted.msg = NULL;
503   bob_wanted.opt = -1;
504   bob_wanted.next_task = &set_bob_ready;
505   bob_wanted.next_task_cls = NULL;
506   bob_ready = GNUNET_NO;
507   carol_wanted.next_task = &prepare_carol_for_alice_and_bob_task;
508   carol_wanted.next_task_cls = NULL;
509   carol_room =
510       GNUNET_CHAT_join_room (is_p2p ? p3.cfg : p1.cfg, "carol", carol_meta,
511                              "test", -1,
512                              &join_cb, &carol_wanted,
513                              &receive_cb, &carol_wanted,
514                              &member_list_cb, &carol_wanted,
515                              NULL, NULL, &carol);
516   if (NULL == carol_room)
517   {
518     GNUNET_SCHEDULER_cancel (kill_task);
519     kill_task = GNUNET_SCHEDULER_NO_TASK;
520     GNUNET_CHAT_leave_room (alice_room);
521     alice_room = NULL;
522     GNUNET_CHAT_leave_room (bob_room);
523     bob_room = NULL;
524     err = 1;
525   }
526 }
527
528
529 static void
530 join_bob_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
531 {
532 #if VERBOSE
533   printf ("Bob joining\n");
534 #endif
535   alice_wanted.meta = bob_meta;
536   alice_wanted.sender = &bob;
537   alice_wanted.msg = NULL;
538   alice_wanted.opt = -1;
539   alice_wanted.next_task = &wait_until_all_ready;
540   alice_wanted.next_task_cls = &join_carol_task;
541   alice_ready = GNUNET_YES;
542   bob_wanted.next_task = &prepare_bob_for_alice_task;
543   bob_wanted.next_task_cls = NULL;
544   bob_ready = GNUNET_NO;
545   bob_room =
546       GNUNET_CHAT_join_room (is_p2p ? p2.cfg : p1.cfg, "bob", bob_meta,
547                              "test", -1,
548                              &join_cb, &bob_wanted,
549                              &receive_cb, &bob_wanted,
550                              &member_list_cb, &bob_wanted, NULL, NULL, &bob);
551   if (NULL == bob_room)
552   {
553     GNUNET_SCHEDULER_cancel (kill_task);
554     kill_task = GNUNET_SCHEDULER_NO_TASK;
555     GNUNET_CHAT_leave_room (alice_room);
556     alice_room = NULL;
557     err = 1;
558   }
559 }
560
561
562 static void
563 join_alice_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
564 {
565 #if VERBOSE
566   printf ("Alice joining\n");
567 #endif
568   alice_wanted.next_task = &join_bob_task;
569   alice_wanted.next_task_cls = NULL;
570   alice_room =
571       GNUNET_CHAT_join_room (p1.cfg, "alice", alice_meta,
572                              "test", -1,
573                              &join_cb, &alice_wanted,
574                              &receive_cb, &alice_wanted,
575                              &member_list_cb, &alice_wanted,
576                              NULL, NULL, &alice);
577   if (NULL == alice_room)
578   {
579     GNUNET_SCHEDULER_cancel (kill_task);
580     kill_task = GNUNET_SCHEDULER_NO_TASK;
581     err = 1;
582   }
583 }
584
585
586 static void
587 run (void *cls,
588      char *const *args,
589      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
590 {
591   if (is_p2p)
592   {
593     setup_peer (&p1, "test_chat_peer1.conf");
594     setup_peer (&p2, "test_chat_peer2.conf");
595     setup_peer (&p3, "test_chat_peer3.conf");
596   }
597   else
598     setup_peer (&p1, "test_chat_data.conf");
599
600   memset (&alice_wanted, 0, sizeof (struct Wanted));
601   memset (&bob_wanted, 0, sizeof (struct Wanted));
602   memset (&carol_wanted, 0, sizeof (struct Wanted));
603   alice_wanted.me = "Alice";
604   bob_wanted.me = "Bob";
605   carol_wanted.me = "Carol";
606   alice_meta = GNUNET_CONTAINER_meta_data_create ();
607   GNUNET_CONTAINER_meta_data_insert (alice_meta,
608                                      "<gnunet>",
609                                      EXTRACTOR_METATYPE_TITLE,
610                                      EXTRACTOR_METAFORMAT_UTF8,
611                                      "text/plain",
612                                      "Alice", strlen ("Alice") + 1);
613   bob_meta = GNUNET_CONTAINER_meta_data_create ();
614   GNUNET_CONTAINER_meta_data_insert (bob_meta,
615                                      "<gnunet>",
616                                      EXTRACTOR_METATYPE_TITLE,
617                                      EXTRACTOR_METAFORMAT_UTF8,
618                                      "text/plain", "Bob", strlen ("Bob") + 1);
619   carol_meta = GNUNET_CONTAINER_meta_data_create ();
620   GNUNET_CONTAINER_meta_data_insert (carol_meta,
621                                      "<gnunet>",
622                                      EXTRACTOR_METATYPE_TITLE,
623                                      EXTRACTOR_METAFORMAT_UTF8,
624                                      "text/plain",
625                                      "Carol", strlen ("Carol") + 1);
626   kill_task = GNUNET_SCHEDULER_add_delayed (KILL_TIMEOUT, &timeout_kill, NULL);
627   GNUNET_SCHEDULER_add_now (&join_alice_task, NULL);
628 }
629
630
631 int
632 main (int argc, char *argv[])
633 {
634   char *const argvx[] = {
635     "test-chat",
636     "-c",
637     "test_chat_data.conf",
638 #if VERBOSE
639     "-L", "DEBUG",
640 #endif
641     NULL
642   };
643   struct GNUNET_GETOPT_CommandLineOption options[] = {
644     GNUNET_GETOPT_OPTION_END
645   };
646
647   GNUNET_log_setup ("test_chat",
648 #if VERBOSE
649                     "DEBUG",
650 #else
651                     "WARNING",
652 #endif
653                     NULL);
654   if (strstr (argv[0], "p2p") != NULL)
655   {
656     is_p2p = GNUNET_YES;
657   }
658   GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1,
659                       argvx, "test-chat", "nohelp", options, &run, NULL);
660   stop_arm (&p1);
661   GNUNET_CONTAINER_meta_data_destroy (alice_meta);
662   GNUNET_CONTAINER_meta_data_destroy (bob_meta);
663   GNUNET_CONTAINER_meta_data_destroy (carol_meta);
664   if (is_p2p)
665   {
666     GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-1/");
667     GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-2/");
668     GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-3/");
669   }
670   else
671     GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat/");
672   return err;
673 }
674
675 /* end of test_chat_private.c */