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