fixed byte conversion bugs
[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       if (&peer1 == peer)   /* Peer1 has finished writing; should read now */
222         {
223           peer->io_read_handle =
224             GNUNET_STREAM_read ((struct GNUNET_STREAM_Socket *)
225                                 peer->socket,
226                                 GNUNET_TIME_relative_multiply
227                                 (GNUNET_TIME_UNIT_SECONDS, 5),
228                                 &input_processor,
229                                 cls);
230           GNUNET_assert (NULL!=peer->io_read_handle);
231         }
232     }
233 }
234
235
236 /**
237  * Function executed after stream has been established
238  *
239  * @param cls the closure from GNUNET_STREAM_open
240  * @param socket socket to use to communicate with the other side (read/write)
241  */
242 static void 
243 stream_open_cb (void *cls,
244                 struct GNUNET_STREAM_Socket *socket)
245 {
246   struct PeerData *peer;
247
248   GNUNET_assert (socket == peer1.socket);
249   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
250               "%s: Stream established from peer1\n",
251               GNUNET_i2s (&peer1.our_id));
252   peer = (struct PeerData *) cls;
253   peer->bytes_wrote = 0;
254   GNUNET_assert (socket == peer1.socket);
255   GNUNET_assert (socket == peer->socket);
256   peer->io_write_handle = GNUNET_STREAM_write (peer->socket, /* socket */
257                                                (void *) data, /* data */
258                                                strlen(data),
259                                                GNUNET_TIME_relative_multiply
260                                                (GNUNET_TIME_UNIT_SECONDS, 5),
261                                                &write_completion,
262                                          cls);
263   GNUNET_assert (NULL != peer->io_write_handle);
264 }
265
266
267 /**
268  * Input processor
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 data traffic from the other side
273  * @param size the number of bytes available in data read 
274  * @return number of bytes of processed from 'data' (any data remaining should be
275  *         given to the next time the read processor is called).
276  */
277 static size_t
278 input_processor (void *cls,
279                  enum GNUNET_STREAM_Status status,
280                  const void *input_data,
281                  size_t size)
282 {
283   struct PeerData *peer;
284
285   peer = (struct PeerData *) cls;
286
287   GNUNET_assert (GNUNET_STREAM_OK == status);
288   GNUNET_assert (size < strlen (data));
289   GNUNET_assert (strncmp ((const char *) data + peer->bytes_read, 
290                           (const char *) input_data,
291                           size));
292   peer->bytes_read += size;
293   
294   if (peer->bytes_read < strlen (data))
295     {
296       peer->io_read_handle = GNUNET_STREAM_read ((struct GNUNET_STREAM_Socket *)
297                                                  peer->socket,
298                                                  GNUNET_TIME_relative_multiply
299                                                  (GNUNET_TIME_UNIT_SECONDS, 5),
300                                                  &input_processor,
301                                                  cls);
302       GNUNET_assert (NULL != peer->io_read_handle);
303     }
304   else 
305     {
306       if (&peer2 == peer)    /* Peer2 has completed reading; should write */
307         {
308           peer->bytes_wrote = 0;
309           peer->io_write_handle = 
310             GNUNET_STREAM_write (peer->socket,
311                                  data,
312                                  strlen(data),
313                                  GNUNET_TIME_relative_multiply
314                                  (GNUNET_TIME_UNIT_SECONDS, 5),
315                                  &write_completion,
316                                  cls);
317         }
318       else                      /* Peer1 has completed reading. End of tests */
319         {
320           GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
321         }
322     } 
323   return size;
324 }
325
326   
327 /**
328  * Scheduler call back; to be executed when a new stream is connected
329  * Called from listen connect for peer2
330  */
331 static void
332 stream_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
333 {
334   read_task = GNUNET_SCHEDULER_NO_TASK;
335   GNUNET_assert (NULL != cls);
336   peer2.bytes_read = 0;
337   peer2.io_read_handle =
338     GNUNET_STREAM_read ((struct GNUNET_STREAM_Socket *) cls,
339                         GNUNET_TIME_relative_multiply
340                         (GNUNET_TIME_UNIT_SECONDS, 5),
341                         &input_processor,
342                         (void *) &peer2);
343   GNUNET_assert (NULL != peer2.io_read_handle);
344 }
345
346
347 /**
348  * Functions of this type are called upon new stream connection from other peers
349  *
350  * @param cls the closure from GNUNET_STREAM_listen
351  * @param socket the socket representing the stream
352  * @param initiator the identity of the peer who wants to establish a stream
353  *            with us
354  * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the
355  *             stream (the socket will be invalid after the call)
356  */
357 static int
358 stream_listen_cb (void *cls,
359            struct GNUNET_STREAM_Socket *socket,
360            const struct GNUNET_PeerIdentity *initiator)
361 {
362   GNUNET_assert (NULL != socket);
363   GNUNET_assert (NULL != initiator);
364   GNUNET_assert (socket != peer1.socket);
365
366   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
367               "%s: Peer connected: %s\n",
368               GNUNET_i2s (&peer2.our_id),
369               GNUNET_i2s(initiator));
370
371   peer2.socket = socket;
372   read_task = GNUNET_SCHEDULER_add_now (&stream_read, (void *) socket);
373   return GNUNET_OK;
374 }
375
376
377 /**
378  * Callback to be called when testing peer group is ready
379  *
380  * @param cls NULL
381  * @param emsg NULL on success
382  */
383 void
384 peergroup_ready (void *cls, const char *emsg)
385 {
386   if (NULL != emsg)
387     {
388       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
389                   "Starting peer group failed: %s\n", emsg);
390       return;
391     }
392   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
393               "Peer group is now ready\n");
394   
395   GNUNET_assert (2 == GNUNET_TESTING_daemons_running (pg));
396   
397   d1 = GNUNET_TESTING_daemon_get (pg, 0);
398   GNUNET_assert (NULL != d1);
399   
400   d2 = GNUNET_TESTING_daemon_get (pg, 1);
401   GNUNET_assert (NULL != d2);
402
403   GNUNET_TESTING_get_peer_identity (d1->cfg,
404                                     &peer1.our_id);
405   GNUNET_TESTING_get_peer_identity (d2->cfg,
406                                     &peer2.our_id);
407   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
408               "%s : %s\n",
409               GNUNET_i2s (&peer1.our_id),
410               GNUNET_i2s (&d1->id));
411   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412               "%s : %s\n",
413               GNUNET_i2s (&peer2.our_id),
414               GNUNET_i2s (&d2->id));
415
416   peer2_listen_socket = GNUNET_STREAM_listen (d2->cfg,
417                                               10, /* App port */
418                                               &stream_listen_cb,
419                                               NULL);
420   GNUNET_assert (NULL != peer2_listen_socket);
421
422   /* Connect to stream library */
423   peer1.socket = GNUNET_STREAM_open (d1->cfg,
424                                      &d2->id,         /* Null for local peer? */
425                                      10,           /* App port */
426                                      &stream_open_cb,
427                                      &peer1);
428   GNUNET_assert (NULL != peer1.socket);
429 }
430
431
432 /**
433  * Initialize framework and start test
434  */
435 static void
436 run (void *cls, char *const *args, const char *cfgfile,
437      const struct GNUNET_CONFIGURATION_Handle *cfg)
438 {
439   struct GNUNET_TESTING_Host *hosts; /* FIXME: free hosts (DLL) */
440
441   /* GNUNET_log_setup ("test_stream_local", */
442   /*                   "DEBUG", */
443   /*                   NULL); */
444
445   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
446               "Starting test\n");
447   /* Duplicate the configuration */
448   config = GNUNET_CONFIGURATION_dup (cfg);
449
450   hosts = GNUNET_TESTING_hosts_load (config);
451   
452   pg = GNUNET_TESTING_peergroup_start (config,
453                                        2,
454                                        GNUNET_TIME_relative_multiply
455                                        (GNUNET_TIME_UNIT_SECONDS, 3),
456                                        NULL,
457                                        &peergroup_ready,
458                                        NULL,
459                                        hosts);
460   GNUNET_assert (NULL != pg);
461                                        
462   abort_task =
463     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
464                                   (GNUNET_TIME_UNIT_SECONDS, 40), &do_abort,
465                                   NULL);
466 }
467
468 /**
469  * Main function
470  */
471 int main (int argc, char **argv)
472 {
473   int ret;
474
475   char *argv2[] = { "test-stream-local",
476                     "-L", "DEBUG",
477                     "-c", "test_stream_local.conf",
478                     NULL};
479   
480   struct GNUNET_GETOPT_CommandLineOption options[] = {
481     GNUNET_GETOPT_OPTION_END
482   };
483
484   ret =
485       GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
486                           "test-stream-local", "nohelp", options, &run, NULL);
487
488   if (GNUNET_OK != ret)
489   {
490     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n",
491                 ret);
492     return 1;
493   }
494   if (GNUNET_SYSERR == result)
495   {
496     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n");
497     return 1;
498   }
499   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test ok\n");
500   return 0;
501 }