-fixed mesh application types array and makefile
[oweals/gnunet.git] / src / stream / test_stream_2peers.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.c
23  * @brief Stream API testing between 2 peers using testing API
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
35 #define VERBOSE 1
36
37 /**
38  * Number of peers
39  */
40 #define NUM_PEERS 2
41
42 /**
43  * Structure for holding peer's sockets and IO Handles
44  */
45 struct PeerData
46 {
47   /**
48    * Peer's stream socket
49    */
50   struct GNUNET_STREAM_Socket *socket;
51
52   /**
53    * Peer's io write handle
54    */
55   struct GNUNET_STREAM_IOWriteHandle *io_write_handle;
56
57   /**
58    * Peer's io read handle
59    */
60   struct GNUNET_STREAM_IOReadHandle *io_read_handle;
61
62   /**
63    * Peer's shutdown handle
64    */
65   struct GNUNET_STREAM_ShutdownHandle *shutdown_handle;
66
67   /**
68    * Our Peer id
69    */
70   struct GNUNET_PeerIdentity our_id;
71
72   /**
73    * Bytes the peer has written
74    */
75   unsigned int bytes_wrote;
76
77   /**
78    * Byte the peer has read
79    */
80   unsigned int bytes_read;
81 };
82
83 /**
84  * The current peer group
85  */
86 static struct GNUNET_TESTING_PeerGroup *pg;
87
88 /**
89  * Peer 1 daemon
90  */
91 static struct GNUNET_TESTING_Daemon *d1;
92
93 /**
94  * Peer 2 daemon
95  */
96 static struct GNUNET_TESTING_Daemon *d2;
97
98 static struct PeerData peer1;
99 static struct PeerData peer2;
100 static struct GNUNET_STREAM_ListenSocket *peer2_listen_socket;
101 static struct GNUNET_CONFIGURATION_Handle *config;
102
103 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
104
105 static char *data = "ABCD";
106 static int result;
107
108 static int writing_success;
109 static int reading_success;
110
111
112 /**
113  * Input processor
114  *
115  * @param cls the closure from GNUNET_STREAM_write/read
116  * @param status the status of the stream at the time this function is called
117  * @param data traffic from the other side
118  * @param size the number of bytes available in data read 
119  * @return number of bytes of processed from 'data' (any data remaining should be
120  *         given to the next time the read processor is called).
121  */
122 static size_t
123 input_processor (void *cls,
124                  enum GNUNET_STREAM_Status status,
125                  const void *input_data,
126                  size_t size);
127
128 /**
129  * Task for calling STREAM_read
130  *
131  * @param cls the peer data entity
132  * @param tc the task context
133  */
134 static void
135 stream_read_task (void *cls,
136                   const struct GNUNET_SCHEDULER_TaskContext *tc)
137 {
138   struct PeerData *peer = cls;
139   
140   peer->io_read_handle = GNUNET_STREAM_read (peer->socket,
141                                              GNUNET_TIME_relative_multiply
142                                              (GNUNET_TIME_UNIT_SECONDS, 5),
143                                              &input_processor,
144                                              peer);
145   GNUNET_assert (NULL != peer->io_read_handle);
146 }
147
148 /**
149  * The write completion function; called upon writing some data to stream or
150  * upon error
151  *
152  * @param cls the closure from GNUNET_STREAM_write/read
153  * @param status the status of the stream at the time this function is called
154  * @param size the number of bytes read or written
155  */
156 static void 
157 write_completion (void *cls,
158                   enum GNUNET_STREAM_Status status,
159                   size_t size);
160
161
162 /**
163  * Task for calling STREAM_write
164  *
165  * @param cls the peer data entity
166  * @param tc the task context
167  */
168 static void
169 stream_write_task (void *cls,
170                    const struct GNUNET_SCHEDULER_TaskContext *tc)
171 {
172   struct PeerData *peer = cls;
173   
174   peer->io_write_handle = 
175     GNUNET_STREAM_write (peer->socket,
176                          (void *) data,
177                          strlen(data) - peer->bytes_wrote,
178                          GNUNET_TIME_relative_multiply
179                          (GNUNET_TIME_UNIT_SECONDS, 5),
180                          &write_completion,
181                          peer);
182  
183   GNUNET_assert (NULL != peer->io_write_handle);
184  }
185
186
187 /**
188  * Check whether peers successfully shut down.
189  */
190 static void
191 peergroup_shutdown_callback (void *cls, const char *emsg)
192 {
193   if (emsg != NULL)
194   {
195     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
196                 "Shutdown of peers failed!\n");
197   }
198   else
199   {
200     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
201                 "All peers successfully shut down!\n");
202   }
203   GNUNET_CONFIGURATION_destroy (config);
204 }
205
206
207 /**
208  * Close sockets and stop testing deamons nicely
209  */
210 static void
211 do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
212 {
213   if (NULL != peer1.socket)
214     GNUNET_STREAM_close (peer1.socket);
215   if (NULL != peer2.socket)
216     GNUNET_STREAM_close (peer2.socket);
217   if (NULL != peer2_listen_socket)
218     GNUNET_STREAM_listen_close (peer2_listen_socket);
219
220   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n");
221   if (0 != abort_task)
222   {
223     GNUNET_SCHEDULER_cancel (abort_task);
224   }
225
226   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Wait\n");
227
228   GNUNET_TESTING_daemons_stop (pg,
229                                GNUNET_TIME_relative_multiply
230                                (GNUNET_TIME_UNIT_SECONDS, 5),
231                                &peergroup_shutdown_callback,
232                                NULL);
233 }
234
235
236 /**
237  * Completion callback for shutdown
238  *
239  * @param cls the closure from GNUNET_STREAM_shutdown call
240  * @param operation the operation that was shutdown (SHUT_RD, SHUT_WR,
241  *          SHUT_RDWR) 
242  */
243 static void 
244 shutdown_completion (void *cls,
245                      int operation)
246 {
247   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
248               "STREAM shutdown successful\n");
249   GNUNET_SCHEDULER_add_now (&do_close,
250                             cls);
251 }
252
253
254
255 /**
256  * Shutdown sockets gracefully
257  */
258 static void
259 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
260 {
261   peer1.shutdown_handle = GNUNET_STREAM_shutdown (peer1.socket, 
262                                                   SHUT_RDWR,
263                                                   &shutdown_completion,
264                                                   cls);
265 }
266
267
268 /**
269  * Something went wrong and timed out. Kill everything and set error flag
270  */
271 static void
272 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
273 {
274   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n");
275   result = GNUNET_SYSERR;
276   abort_task = 0;
277   do_close (cls, tc);  
278 }
279
280
281 /**
282  * The write completion function; called upon writing some data to stream or
283  * upon error
284  *
285  * @param cls the closure from GNUNET_STREAM_write/read
286  * @param status the status of the stream at the time this function is called
287  * @param size the number of bytes read or written
288  */
289 static void 
290 write_completion (void *cls,
291                   enum GNUNET_STREAM_Status status,
292                   size_t size)
293 {
294   struct PeerData *peer=cls;
295
296   GNUNET_assert (GNUNET_STREAM_OK == status);
297   GNUNET_assert (size <= strlen (data));
298   peer->bytes_wrote += size;
299
300   if (peer->bytes_wrote < strlen(data)) /* Have more data to send */
301     {
302       GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
303     }
304   else
305     {
306       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
307                   "Writing completed\n");
308
309       if (&peer1 == peer)   /* Peer1 has finished writing; should read now */
310         {
311           peer->bytes_read = 0;
312           GNUNET_SCHEDULER_add_now (&stream_read_task, peer);
313         }
314       else
315         {
316           writing_success = GNUNET_YES;
317           if (GNUNET_YES == reading_success)
318             GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
319         }
320     }
321 }
322
323
324 /**
325  * Function executed after stream has been established
326  *
327  * @param cls the closure from GNUNET_STREAM_open
328  * @param socket socket to use to communicate with the other side (read/write)
329  */
330 static void 
331 stream_open_cb (void *cls,
332                 struct GNUNET_STREAM_Socket *socket)
333 {
334   struct PeerData *peer=cls;
335   
336   GNUNET_assert (&peer1 == peer);
337   GNUNET_assert (socket == peer1.socket);
338   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
339               "%s: Stream established from peer1\n",
340               GNUNET_i2s (&peer1.our_id));
341   peer->bytes_wrote = 0;
342   GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
343 }
344
345
346 /**
347  * Input processor
348  *
349  * @param cls the closure from GNUNET_STREAM_write/read
350  * @param status the status of the stream at the time this function is called
351  * @param data traffic from the other side
352  * @param size the number of bytes available in data read 
353  * @return number of bytes of processed from 'data' (any data remaining should be
354  *         given to the next time the read processor is called).
355  */
356 static size_t
357 input_processor (void *cls,
358                  enum GNUNET_STREAM_Status status,
359                  const void *input_data,
360                  size_t size)
361 {
362   struct PeerData *peer;
363
364   peer = (struct PeerData *) cls;
365
366   if (GNUNET_STREAM_TIMEOUT == status)
367     {
368       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
369                   "Read operation timedout - reading again!\n");
370       GNUNET_assert (0 == size);
371       GNUNET_SCHEDULER_add_now (&stream_read_task, peer);
372       return 0;
373     }
374
375   GNUNET_assert (GNUNET_STREAM_OK == status);
376   GNUNET_assert (size <= strlen (data));
377   GNUNET_assert (0 == strncmp ((const char *) data + peer->bytes_read, 
378                                (const char *) input_data,
379                                size));
380   peer->bytes_read += size;
381   
382   if (peer->bytes_read < strlen (data))
383     {
384       GNUNET_SCHEDULER_add_now (&stream_read_task, peer);
385     }
386   else 
387     {
388       if (&peer2 == peer)    /* Peer2 has completed reading; should write */
389         {
390           peer->bytes_wrote = 0;
391           GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
392         }
393       else                      /* Peer1 has completed reading. End of tests */
394         {
395           reading_success = GNUNET_YES;
396           if (GNUNET_YES == writing_success)
397             GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
398         }
399     }
400   return size;
401 }
402
403   
404 /**
405  * Functions of this type are called upon new stream connection from other peers
406  *
407  * @param cls the closure from GNUNET_STREAM_listen
408  * @param socket the socket representing the stream
409  * @param initiator the identity of the peer who wants to establish a stream
410  *            with us
411  * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the
412  *             stream (the socket will be invalid after the call)
413  */
414 static int
415 stream_listen_cb (void *cls,
416                   struct GNUNET_STREAM_Socket *socket,
417                   const struct GNUNET_PeerIdentity *initiator)
418 {
419   GNUNET_assert (NULL != socket);
420   GNUNET_assert (NULL != initiator);
421   GNUNET_assert (socket != peer1.socket);
422
423   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424               "%s: Peer connected: %s\n",
425               GNUNET_i2s (&peer2.our_id),
426               GNUNET_i2s(initiator));
427
428   peer2.socket = socket;
429   peer2.bytes_read = 0;
430   GNUNET_SCHEDULER_add_now (&stream_read_task, &peer2);
431   return GNUNET_OK;
432 }
433
434
435 /**
436  * Callback to be called when testing peer group is ready
437  *
438  * @param cls NULL
439  * @param emsg NULL on success
440  */
441 void
442 peergroup_ready (void *cls, const char *emsg)
443 {
444   if (NULL != emsg)
445     {
446       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
447                   "Starting peer group failed: %s\n", emsg);
448       return;
449     }
450   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
451               "Peer group is now ready\n");
452   
453   GNUNET_assert (2 == GNUNET_TESTING_daemons_running (pg));
454   
455   d1 = GNUNET_TESTING_daemon_get (pg, 0);
456   GNUNET_assert (NULL != d1);
457   
458   d2 = GNUNET_TESTING_daemon_get (pg, 1);
459   GNUNET_assert (NULL != d2);
460
461   GNUNET_TESTING_get_peer_identity (d1->cfg,
462                                     &peer1.our_id);
463   GNUNET_TESTING_get_peer_identity (d2->cfg,
464                                     &peer2.our_id);
465   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
466               "%s : %s\n",
467               GNUNET_i2s (&peer1.our_id),
468               GNUNET_i2s (&d1->id));
469   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
470               "%s : %s\n",
471               GNUNET_i2s (&peer2.our_id),
472               GNUNET_i2s (&d2->id));
473
474   peer2_listen_socket = GNUNET_STREAM_listen (d2->cfg,
475                                               10, /* App port */
476                                               &stream_listen_cb,
477                                               NULL);
478   GNUNET_assert (NULL != peer2_listen_socket);
479
480   /* Connect to stream library */
481   peer1.socket = GNUNET_STREAM_open (d1->cfg,
482                                      &d2->id,         /* Null for local peer? */
483                                      10,           /* App port */
484                                      &stream_open_cb,
485                                      &peer1);
486   GNUNET_assert (NULL != peer1.socket);
487 }
488
489
490 /**
491  * Initialize framework and start test
492  */
493 static void
494 run (void *cls, char *const *args, const char *cfgfile,
495      const struct GNUNET_CONFIGURATION_Handle *cfg)
496 {
497   struct GNUNET_TESTING_Host *hosts; /* FIXME: free hosts (DLL) */
498
499   GNUNET_log_setup ("test_stream_2peers",
500                     "DEBUG",
501                     NULL);
502
503   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
504               "Starting test\n");
505   /* Duplicate the configuration */
506   config = GNUNET_CONFIGURATION_dup (cfg);
507
508   hosts = GNUNET_TESTING_hosts_load (config);
509   
510   pg = GNUNET_TESTING_peergroup_start (config,
511                                        2,
512                                        GNUNET_TIME_relative_multiply
513                                        (GNUNET_TIME_UNIT_SECONDS, 3),
514                                        NULL,
515                                        &peergroup_ready,
516                                        NULL,
517                                        hosts);
518   GNUNET_assert (NULL != pg);
519                                        
520   abort_task =
521     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
522                                   (GNUNET_TIME_UNIT_SECONDS, 40), &do_abort,
523                                   NULL);
524 }
525
526 /**
527  * Main function
528  */
529 int main (int argc, char **argv)
530 {
531   int ret;
532
533   char *argv2[] = { "test-stream-2peers",
534                     "-L", "DEBUG",
535                     "-c", "test_stream_local.conf",
536                     NULL};
537   
538   struct GNUNET_GETOPT_CommandLineOption options[] = {
539     GNUNET_GETOPT_OPTION_END
540   };
541
542   ret =
543       GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
544                           "test-stream-2peers", "nohelp", options, &run, NULL);
545
546   if (GNUNET_OK != ret)
547   {
548     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n",
549                 ret);
550     return 1;
551   }
552   if (GNUNET_SYSERR == result)
553   {
554     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n");
555     return 1;
556   }
557   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test ok\n");
558   return 0;
559 }