-added stream listen success callback
[oweals/gnunet.git] / src / stream / test_stream_2peers_halfclose.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011, 2012 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 stream/test_stream_2peers_halfclose.c
23  * @brief Testcases for Stream API halfclosed connections between 2 peers
24  * @author Sree Harsha Totakura
25  */
26
27 #include <string.h>
28
29 #include "platform.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_mesh_service.h"
32 #include "gnunet_stream_lib.h"
33 #include "gnunet_testing_lib.h"
34 #include "gnunet_scheduler_lib.h"
35
36 #define VERBOSE 1
37
38 /**
39  * Number of peers
40  */
41 #define NUM_PEERS 2
42
43 #define TIME_REL_SECS(sec) \
44   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
45
46 /**
47  * Structure for holding peer's sockets and IO Handles
48  */
49 struct PeerData
50 {
51   /**
52    * Peer's stream socket
53    */
54   struct GNUNET_STREAM_Socket *socket;
55
56   /**
57    * Peer's io write handle
58    */
59   struct GNUNET_STREAM_IOWriteHandle *io_write_handle;
60
61   /**
62    * Peer's io read handle
63    */
64   struct GNUNET_STREAM_IOReadHandle *io_read_handle;
65
66   /**
67    * Peer's shutdown handle
68    */
69   struct GNUNET_STREAM_ShutdownHandle *shutdown_handle;
70
71   /**
72    * Our Peer id
73    */
74   struct GNUNET_PeerIdentity our_id;
75
76   /**
77    * Bytes the peer has written
78    */
79   unsigned int bytes_wrote;
80
81   /**
82    * Byte the peer has read
83    */
84   unsigned int bytes_read;
85
86   /**
87    * GNUNET_YES if the peer has successfully completed the current test
88    */
89   unsigned int test_ok;
90
91   /**
92    * The shutdown operation that has to be used by the stream_shutdown_task
93    */
94   int shutdown_operation;
95 };
96
97 /**
98  * The current peer group
99  */
100 static struct GNUNET_TESTING_PeerGroup *pg;
101
102 /**
103  * Peer 1 daemon
104  */
105 static struct GNUNET_TESTING_Daemon *d1;
106
107 /**
108  * Peer 2 daemon
109  */
110 static struct GNUNET_TESTING_Daemon *d2;
111
112
113 /**
114  * Peer1 writes first and then calls for SHUT_WR
115  * Peer2 reads first and then calls for SHUT_RD
116  * Attempt to write again by Peer1 should be rejected
117  * Attempt to read again by Peer2 should be rejected
118  * Peer1 then reads from Peer2 which writes
119  */
120 static struct PeerData peer1;
121 static struct PeerData peer2;
122 static struct GNUNET_STREAM_ListenSocket *peer2_listen_socket;
123 static struct GNUNET_CONFIGURATION_Handle *config;
124
125 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
126 static GNUNET_SCHEDULER_TaskIdentifier read_task;
127
128 static char *data = "ABCD";
129 static int result;
130
131 /**
132  * Enumeration for various tests that are to be passed in the same order as
133  * below
134  */
135 enum Test
136   {
137     /**
138      * Peer1 writing; Peer2 reading
139      */
140     PEER1_WRITE,
141
142     /**
143      * Peer1 write shutdown; Peer2 should get an error when it tries to read;
144      */
145     PEER1_WRITE_SHUTDOWN,
146
147     /**
148      * Peer1 reads; Peer2 writes (connection is halfclosed)
149      */
150     PEER1_HALFCLOSE_READ,
151
152     /**
153      * Peer1 attempts to write; Should fail with stream already shutdown error
154      */
155     PEER1_HALFCLOSE_WRITE_FAIL,
156
157     /**
158      * Peer1 read shutdown; Peer2 should get stream shutdown error during write
159      */
160     PEER1_READ_SHUTDOWN,
161
162     /**
163      * All tests successfully finished
164      */
165     SUCCESS
166   };
167
168 /**
169  * Current running test
170  */
171 enum Test current_test;
172
173 /**
174  * Input processor
175  *
176  * @param cls the closure from GNUNET_STREAM_write/read
177  * @param status the status of the stream at the time this function is called
178  * @param data traffic from the other side
179  * @param size the number of bytes available in data read 
180  * @return number of bytes of processed from 'data' (any data remaining should be
181  *         given to the next time the read processor is called).
182  */
183 static size_t
184 input_processor (void *cls,
185                  enum GNUNET_STREAM_Status status,
186                  const void *input_data,
187                  size_t size);
188
189
190 /**
191  * The transition function; responsible for the transitions among tests
192  */
193 static void
194 transition();
195
196
197 /**
198  * Task for calling STREAM_read
199  *
200  * @param cls the peer data entity
201  * @param tc the task context
202  */
203 static void
204 stream_read_task (void *cls,
205                   const struct GNUNET_SCHEDULER_TaskContext *tc)
206 {
207   struct PeerData *peer = cls;
208   
209   peer->io_read_handle = GNUNET_STREAM_read (peer->socket,
210                                              GNUNET_TIME_relative_multiply
211                                              (GNUNET_TIME_UNIT_SECONDS, 5),
212                                              &input_processor,
213                                              cls);
214   switch (current_test)
215     {
216     case PEER1_WRITE_SHUTDOWN:
217       GNUNET_assert (&peer2 == peer);
218       GNUNET_assert (NULL == peer->io_read_handle);
219       transition ();            /* to PEER1_HALFCLOSE_READ */
220       break;
221     default:
222       GNUNET_assert (NULL != peer->io_read_handle);
223     }
224 }
225
226
227 /**
228  * The write completion function; called upon writing some data to stream or
229  * upon error
230  *
231  * @param cls the closure from GNUNET_STREAM_write/read
232  * @param status the status of the stream at the time this function is called
233  * @param size the number of bytes read or written
234  */
235 static void 
236 write_completion (void *cls,
237                   enum GNUNET_STREAM_Status status,
238                   size_t size);
239
240
241 /**
242  * Task for calling STREAM_write
243  *
244  * @param cls the peer data entity
245  * @param tc the task context
246  */
247 static void
248 stream_write_task (void *cls,
249                    const struct GNUNET_SCHEDULER_TaskContext *tc)
250 {
251   struct PeerData *peer = cls;
252   
253   peer->io_write_handle = 
254     GNUNET_STREAM_write (peer->socket,
255                          (void *) data,
256                          strlen(data) - peer->bytes_wrote,
257                          GNUNET_TIME_relative_multiply
258                          (GNUNET_TIME_UNIT_SECONDS, 5),
259                          &write_completion,
260                          peer);
261   switch (current_test)
262     {
263     case PEER1_HALFCLOSE_WRITE_FAIL:
264       GNUNET_assert (&peer1 == peer);
265       GNUNET_assert (NULL == peer->io_write_handle);
266       transition();             /* To PEER1_READ_SHUTDOWN */
267       break;
268     case PEER1_READ_SHUTDOWN:
269       GNUNET_assert (&peer2 == peer);
270       GNUNET_assert (NULL == peer->io_write_handle);
271       transition ();            /* To SUCCESS */
272       break;
273     default:
274         GNUNET_assert (NULL != peer->io_write_handle);
275     }
276 }
277
278
279 /**
280  * Check whether peers successfully shut down.
281  */
282 static void
283 peergroup_shutdown_callback (void *cls, const char *emsg)
284 {
285   if (emsg != NULL)
286   {
287     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
288                 "Shutdown of peers failed!\n");
289   }
290   else
291   {
292     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
293                 "All peers successfully shut down!\n");
294   }
295   GNUNET_CONFIGURATION_destroy (config);
296 }
297
298
299 /**
300  * Close sockets and stop testing deamons nicely
301  */
302 static void
303 do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
304 {
305   if (NULL != peer1.socket)
306     GNUNET_STREAM_close (peer1.socket);
307   if (NULL != peer2.socket)
308     GNUNET_STREAM_close (peer2.socket);
309   if (NULL != peer2_listen_socket)
310     GNUNET_STREAM_listen_close (peer2_listen_socket);
311
312   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n");
313   if (0 != abort_task)
314   {
315     GNUNET_SCHEDULER_cancel (abort_task);
316   }
317
318   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Wait\n");
319
320   GNUNET_TESTING_daemons_stop (pg,
321                                GNUNET_TIME_relative_multiply
322                                (GNUNET_TIME_UNIT_SECONDS, 5),
323                                &peergroup_shutdown_callback,
324                                NULL);
325 }
326
327
328 /**
329  * Completion callback for shutdown
330  *
331  * @param cls the closure from GNUNET_STREAM_shutdown call
332  * @param operation the operation that was shutdown (SHUT_RD, SHUT_WR,
333  *          SHUT_RDWR) 
334  */
335 void 
336 shutdown_completion (void *cls,
337                      int operation)
338 {
339   switch (current_test)
340     {
341     case PEER1_WRITE:
342       GNUNET_assert (0);
343     case PEER1_WRITE_SHUTDOWN:
344       GNUNET_assert (cls == &peer1);
345       GNUNET_assert (SHUT_WR == operation);
346       peer1.test_ok = GNUNET_YES;
347       /* Peer2 should read with error */
348       peer2.bytes_read = 0;
349       GNUNET_SCHEDULER_add_now (&stream_read_task, &peer2);
350       break;
351     case PEER1_READ_SHUTDOWN:
352       peer1.test_ok = GNUNET_YES;
353       peer2.bytes_wrote = 0;
354       GNUNET_SCHEDULER_add_now (&stream_write_task, &peer2);
355       break;
356     case PEER1_HALFCLOSE_READ:
357     case PEER1_HALFCLOSE_WRITE_FAIL:
358     case SUCCESS:
359       GNUNET_assert (0);        /* We shouldn't reach here */
360     }
361 }
362
363
364 /**
365  * Task for calling STREAM_shutdown
366  *
367  * @param cls the peer entity
368  * @param tc the TaskContext
369  */
370 static void
371 stream_shutdown_task (void *cls,
372                       const struct GNUNET_SCHEDULER_TaskContext *tc)
373 {
374   struct PeerData *peer = cls;
375
376   peer->shutdown_handle = GNUNET_STREAM_shutdown (peer->socket,
377                                                   peer->shutdown_operation,
378                                                   &shutdown_completion,
379                                                   peer);
380   GNUNET_assert (NULL != peer->shutdown_handle);
381 }
382
383
384 /**
385  * Something went wrong and timed out. Kill everything and set error flag
386  */
387 static void
388 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
389 {
390   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n");
391   if (0 != read_task)
392     {
393       GNUNET_SCHEDULER_cancel (read_task);
394     }
395   result = GNUNET_SYSERR;
396   abort_task = 0;
397   do_close (cls, tc);  
398 }
399
400
401 /**
402  * The transition function; responsible for the transitions among tests
403  */
404 static void
405 transition()
406 {
407   if ((GNUNET_YES == peer1.test_ok) && (GNUNET_YES == peer2.test_ok))
408     {
409       peer1.test_ok = GNUNET_NO;
410       peer2.test_ok = GNUNET_NO;
411       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412                   "TEST %d SUCCESSFULL\n", current_test);
413       switch (current_test)
414         {
415         case PEER1_WRITE:
416           current_test = PEER1_WRITE_SHUTDOWN;
417           /* Peer1 should shutdown writing */
418           peer1.shutdown_operation = SHUT_WR;
419           GNUNET_SCHEDULER_add_now (&stream_shutdown_task, &peer1);
420           break;
421         case PEER1_WRITE_SHUTDOWN:
422           current_test = PEER1_HALFCLOSE_READ;
423           /* Peer2 should be able to write successfully */
424           peer2.bytes_wrote = 0;
425           GNUNET_SCHEDULER_add_now (&stream_write_task, &peer2);
426           
427           /* Peer1 should be able to read successfully */
428           peer1.bytes_read = 0;
429           GNUNET_SCHEDULER_add_now (&stream_read_task, &peer1);
430           break;
431         case PEER1_HALFCLOSE_READ:
432           current_test = PEER1_HALFCLOSE_WRITE_FAIL;
433           peer1.bytes_wrote = 0;
434           peer2.bytes_read = 0;
435           peer2.test_ok = GNUNET_YES;
436           GNUNET_SCHEDULER_add_now (&stream_write_task, &peer1);
437           break;
438         case PEER1_HALFCLOSE_WRITE_FAIL:
439           current_test = PEER1_READ_SHUTDOWN;
440           peer1.shutdown_operation = SHUT_RD;
441           GNUNET_SCHEDULER_add_now (&stream_shutdown_task, &peer1);
442           break;
443         case PEER1_READ_SHUTDOWN:
444           current_test = SUCCESS;
445           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
446                       "All tests successful\n");
447           GNUNET_SCHEDULER_add_now (&do_close, NULL);
448           break;
449         case SUCCESS:
450           GNUNET_assert (0);    /* We shouldn't reach here */
451           
452         }
453     }
454 }
455
456 /**
457  * The write completion function; called upon writing some data to stream or
458  * upon error
459  *
460  * @param cls the closure from GNUNET_STREAM_write/read
461  * @param status the status of the stream at the time this function is called
462  * @param size the number of bytes read or written
463  */
464 static void 
465 write_completion (void *cls,
466                   enum GNUNET_STREAM_Status status,
467                   size_t size)
468 {
469   struct PeerData *peer = cls;
470
471   switch (current_test)
472     {
473     case PEER1_WRITE:
474     case PEER1_HALFCLOSE_READ:
475
476     GNUNET_assert (GNUNET_STREAM_OK == status);
477     GNUNET_assert (size <= strlen (data));
478     peer->bytes_wrote += size;
479
480     if (peer->bytes_wrote < strlen(data)) /* Have more data to send */
481       {
482         GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
483       }
484     else
485       {
486         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
487                     "Writing completed\n");
488
489         if (&peer1 == peer)
490           {
491             peer1.test_ok = GNUNET_YES;
492             transition ();       /* to PEER1_WRITE_SHUTDOWN */
493           }
494         else            /* This will happen during PEER1_HALFCLOSE_READ */
495           {
496             peer2.test_ok = GNUNET_YES;
497             transition ();      /* to PEER1_HALFCLOSE_WRITE_FAIL */
498           }
499       }
500     break;
501     case PEER1_HALFCLOSE_WRITE_FAIL:
502       GNUNET_assert (peer == &peer1);
503       GNUNET_assert (GNUNET_STREAM_SHUTDOWN == status);
504       GNUNET_assert (0 == size);
505       peer1.test_ok = GNUNET_YES;
506       break;
507     case PEER1_READ_SHUTDOWN:
508       GNUNET_assert (peer == &peer2);
509       GNUNET_assert (GNUNET_STREAM_SHUTDOWN == status);
510       GNUNET_assert (0 == size);
511       peer2.test_ok = GNUNET_YES;
512       break;
513     case PEER1_WRITE_SHUTDOWN:
514     case SUCCESS:
515       GNUNET_assert (0);        /* We shouldn't reach here */
516     } 
517 }
518
519
520 /**
521  * Function executed after stream has been established
522  *
523  * @param cls the closure from GNUNET_STREAM_open
524  * @param socket socket to use to communicate with the other side (read/write)
525  */
526 static void 
527 stream_open_cb (void *cls,
528                 struct GNUNET_STREAM_Socket *socket)
529 {
530   struct PeerData *peer;
531
532   GNUNET_assert (socket == peer1.socket);
533   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
534               "%s: Stream established from peer1\n",
535               GNUNET_i2s (&peer1.our_id));
536   peer = (struct PeerData *) cls;
537   peer->bytes_wrote = 0;
538   GNUNET_assert (socket == peer1.socket);
539   GNUNET_assert (socket == peer->socket);
540   peer1.test_ok = GNUNET_NO;
541   peer2.test_ok = GNUNET_NO;
542   current_test = PEER1_WRITE;
543   GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
544 }
545
546
547 /**
548  * Input processor
549  *
550  * @param cls the closure from GNUNET_STREAM_write/read
551  * @param status the status of the stream at the time this function is called
552  * @param data traffic from the other side
553  * @param size the number of bytes available in data read 
554  * @return number of bytes of processed from 'data' (any data remaining should be
555  *         given to the next time the read processor is called).
556  */
557 static size_t
558 input_processor (void *cls,
559                  enum GNUNET_STREAM_Status status,
560                  const void *input_data,
561                  size_t size)
562 {
563   struct PeerData *peer;
564
565   peer = (struct PeerData *) cls;
566
567   switch (current_test)
568     {
569     case PEER1_WRITE:
570     case PEER1_HALFCLOSE_READ:
571       if (GNUNET_STREAM_TIMEOUT == status)
572         {
573           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
574                       "Read operation timedout - reading again!\n");
575           GNUNET_assert (0 == size);
576           GNUNET_SCHEDULER_add_now (&stream_read_task, peer);
577           return 0;
578         }
579
580       GNUNET_assert (GNUNET_STREAM_OK == status);
581       GNUNET_assert (size <= strlen (data));
582       GNUNET_assert (0 == strncmp ((const char *) data + peer->bytes_read,
583                                    (const char *) input_data,
584                                    size));
585       peer->bytes_read += size;
586   
587       if (peer->bytes_read < strlen (data))
588         {
589           GNUNET_SCHEDULER_add_now (&stream_read_task, peer);
590         }
591       else  
592         {
593           if (&peer2 == peer) /* Peer2 has completed reading; should write */
594             {
595               peer2.test_ok = GNUNET_YES;
596               transition ();    /* Transition to PEER1_WRITE_SHUTDOWN */
597             }
598           else         /* Peer1 has completed reading. End of tests */
599             {
600               peer1.test_ok = GNUNET_YES;
601               transition ();    /* to PEER1_HALFCLOSE_WRITE_FAIL */
602             }
603         }
604       break;
605     case PEER1_WRITE_SHUTDOWN:
606       GNUNET_assert (GNUNET_STREAM_SHUTDOWN == status);
607       peer2.test_ok = GNUNET_YES;
608       break;
609     case PEER1_HALFCLOSE_WRITE_FAIL:
610     case PEER1_READ_SHUTDOWN:
611     case SUCCESS:
612       GNUNET_assert (0);        /* We shouldn't reach here */
613     }
614   
615   return size;
616 }
617
618   
619 /**
620  * Scheduler call back; to be executed when a new stream is connected
621  * Called from listen connect for peer2
622  */
623 static void
624 stream_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
625 {
626   read_task = GNUNET_SCHEDULER_NO_TASK;
627   GNUNET_assert (NULL != cls);
628   peer2.bytes_read = 0;
629   GNUNET_SCHEDULER_add_now (&stream_read_task, &peer2);
630 }
631
632
633 /**
634  * Functions of this type are called upon new stream connection from other peers
635  *
636  * @param cls the closure from GNUNET_STREAM_listen
637  * @param socket the socket representing the stream
638  * @param initiator the identity of the peer who wants to establish a stream
639  *            with us
640  * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the
641  *             stream (the socket will be invalid after the call)
642  */
643 static int
644 stream_listen_cb (void *cls,
645                   struct GNUNET_STREAM_Socket *socket,
646                   const struct GNUNET_PeerIdentity *initiator)
647 {
648   GNUNET_assert (NULL != socket);
649   GNUNET_assert (NULL != initiator);
650   GNUNET_assert (socket != peer1.socket);
651
652   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
653               "%s: Peer connected: %s\n",
654               GNUNET_i2s (&peer2.our_id),
655               GNUNET_i2s(initiator));
656
657   peer2.socket = socket;
658   /* FIXME: reading should be done right now instead of a scheduled call */
659   read_task = GNUNET_SCHEDULER_add_now (&stream_read, (void *) socket);
660   return GNUNET_OK;
661 }
662
663
664 /**
665  * Listen success callback; connects a peer to stream as client
666  */
667 static void
668 stream_connect (void)
669 {
670   /* Connect to stream library */
671   peer1.socket = GNUNET_STREAM_open (d1->cfg,
672                                      &d2->id,         /* Null for local peer? */
673                                      10,           /* App port */
674                                      &stream_open_cb,
675                                      &peer1,
676                                      GNUNET_STREAM_OPTION_END);
677   GNUNET_assert (NULL != peer1.socket);
678 }
679
680
681 /**
682  * Callback to be called when testing peer group is ready
683  *
684  * @param cls NULL
685  * @param emsg NULL on success
686  */
687 void
688 peergroup_ready (void *cls, const char *emsg)
689 {
690   if (NULL != emsg)
691     {
692       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
693                   "Starting peer group failed: %s\n", emsg);
694       return;
695     }
696   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
697               "Peer group is now ready\n");
698   
699   GNUNET_assert (2 == GNUNET_TESTING_daemons_running (pg));
700   
701   d1 = GNUNET_TESTING_daemon_get (pg, 0);
702   GNUNET_assert (NULL != d1);
703   
704   d2 = GNUNET_TESTING_daemon_get (pg, 1);
705   GNUNET_assert (NULL != d2);
706
707   GNUNET_TESTING_get_peer_identity (d1->cfg,
708                                     &peer1.our_id);
709   GNUNET_TESTING_get_peer_identity (d2->cfg,
710                                     &peer2.our_id);
711   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
712               "%s : %s\n",
713               GNUNET_i2s (&peer1.our_id),
714               GNUNET_i2s (&d1->id));
715   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
716               "%s : %s\n",
717               GNUNET_i2s (&peer2.our_id),
718               GNUNET_i2s (&d2->id));
719
720   peer2_listen_socket = 
721     GNUNET_STREAM_listen (d2->cfg,
722                           10, /* App port */
723                           &stream_listen_cb,
724                           NULL,
725                           GNUNET_STREAM_OPTION_SIGNAL_LISTEN_SUCCESS,
726                           &stream_connect,
727                           GNUNET_STREAM_OPTION_END);
728   GNUNET_assert (NULL != peer2_listen_socket);
729 }
730
731
732 /**
733  * Initialize framework and start test
734  */
735 static void
736 run (void *cls, char *const *args, const char *cfgfile,
737      const struct GNUNET_CONFIGURATION_Handle *cfg)
738 {
739   struct GNUNET_TESTING_Host *hosts; /* FIXME: free hosts (DLL) */
740
741   /* GNUNET_log_setup ("test_stream_local", */
742   /*                   "DEBUG", */
743   /*                   NULL); */
744
745   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
746               "Starting test\n");
747   /* Duplicate the configuration */
748   config = GNUNET_CONFIGURATION_dup (cfg);
749
750   hosts = GNUNET_TESTING_hosts_load (config);
751   
752   pg = GNUNET_TESTING_peergroup_start (config,
753                                        2,
754                                        GNUNET_TIME_relative_multiply
755                                        (GNUNET_TIME_UNIT_SECONDS, 3),
756                                        NULL,
757                                        &peergroup_ready,
758                                        NULL,
759                                        hosts);
760   GNUNET_assert (NULL != pg);
761                                        
762   abort_task =
763     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
764                                   (GNUNET_TIME_UNIT_SECONDS, 40), &do_abort,
765                                   NULL);
766 }
767
768 /**
769  * Main function
770  */
771 int main (int argc, char **argv)
772 {
773   int ret;
774
775   char *argv2[] = { "test-stream-2peers-halfclose",
776                     "-L", "DEBUG",
777                     "-c", "test_stream_local.conf",
778                     NULL};
779   
780   struct GNUNET_GETOPT_CommandLineOption options[] = {
781     GNUNET_GETOPT_OPTION_END
782   };
783
784   ret =
785       GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
786                           "test-stream-2peers-halfclose", "nohelp", options, &run, NULL);
787
788   if (GNUNET_OK != ret)
789   {
790     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n",
791                 ret);
792     return 1;
793   }
794   if (GNUNET_SYSERR == result)
795   {
796     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n");
797     return 1;
798   }
799   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test ok\n");
800   return 0;
801 }