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