2 This file is part of GNUnet.
3 (C) 2011, 2012 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file stream/test_stream_2peers.c
23 * @brief Stream API testing between 2 peers using testing API
24 * @author Sree Harsha Totakura
30 #include "gnunet_util_lib.h"
31 #include "gnunet_mesh_service.h"
32 #include "gnunet_stream_lib.h"
33 #include "gnunet_testing_lib.h"
42 #define TIME_REL_SECS(sec) \
43 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
46 * Structure for holding peer's sockets and IO Handles
51 * Peer's stream socket
53 struct GNUNET_STREAM_Socket *socket;
56 * Peer's io write handle
58 struct GNUNET_STREAM_IOWriteHandle *io_write_handle;
61 * Peer's io read handle
63 struct GNUNET_STREAM_IOReadHandle *io_read_handle;
66 * Peer's shutdown handle
68 struct GNUNET_STREAM_ShutdownHandle *shutdown_handle;
73 struct GNUNET_PeerIdentity our_id;
76 * Bytes the peer has written
78 unsigned int bytes_wrote;
81 * Byte the peer has read
83 unsigned int bytes_read;
87 * The current peer group
89 static struct GNUNET_TESTING_PeerGroup *pg;
94 static struct GNUNET_TESTING_Daemon *d1;
99 static struct GNUNET_TESTING_Daemon *d2;
101 static struct PeerData peer1;
102 static struct PeerData peer2;
103 static struct GNUNET_STREAM_ListenSocket *peer2_listen_socket;
104 static struct GNUNET_CONFIGURATION_Handle *config;
106 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
108 static char *data = "ABCD";
111 static int writing_success;
112 static int reading_success;
118 * @param cls the closure from GNUNET_STREAM_write/read
119 * @param status the status of the stream at the time this function is called
120 * @param data traffic from the other side
121 * @param size the number of bytes available in data read
122 * @return number of bytes of processed from 'data' (any data remaining should be
123 * given to the next time the read processor is called).
126 input_processor (void *cls,
127 enum GNUNET_STREAM_Status status,
128 const void *input_data,
132 * Task for calling STREAM_read
134 * @param cls the peer data entity
135 * @param tc the task context
138 stream_read_task (void *cls,
139 const struct GNUNET_SCHEDULER_TaskContext *tc)
141 struct PeerData *peer = cls;
143 peer->io_read_handle = GNUNET_STREAM_read (peer->socket,
144 GNUNET_TIME_relative_multiply
145 (GNUNET_TIME_UNIT_SECONDS, 5),
148 GNUNET_assert (NULL != peer->io_read_handle);
152 * The write completion function; called upon writing some data to stream or
155 * @param cls the closure from GNUNET_STREAM_write/read
156 * @param status the status of the stream at the time this function is called
157 * @param size the number of bytes read or written
160 write_completion (void *cls,
161 enum GNUNET_STREAM_Status status,
166 * Task for calling STREAM_write
168 * @param cls the peer data entity
169 * @param tc the task context
172 stream_write_task (void *cls,
173 const struct GNUNET_SCHEDULER_TaskContext *tc)
175 struct PeerData *peer = cls;
177 peer->io_write_handle =
178 GNUNET_STREAM_write (peer->socket,
180 strlen(data) - peer->bytes_wrote,
181 GNUNET_TIME_relative_multiply
182 (GNUNET_TIME_UNIT_SECONDS, 5),
186 GNUNET_assert (NULL != peer->io_write_handle);
191 * Check whether peers successfully shut down.
194 peergroup_shutdown_callback (void *cls, const char *emsg)
198 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
199 "Shutdown of peers failed!\n");
203 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
204 "All peers successfully shut down!\n");
206 GNUNET_CONFIGURATION_destroy (config);
211 * Close sockets and stop testing deamons nicely
214 do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
216 if (NULL != peer1.socket)
217 GNUNET_STREAM_close (peer1.socket);
218 if (NULL != peer2.socket)
219 GNUNET_STREAM_close (peer2.socket);
220 if (NULL != peer2_listen_socket)
221 GNUNET_STREAM_listen_close (peer2_listen_socket);
223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n");
226 GNUNET_SCHEDULER_cancel (abort_task);
229 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Wait\n");
231 GNUNET_TESTING_daemons_stop (pg,
232 GNUNET_TIME_relative_multiply
233 (GNUNET_TIME_UNIT_SECONDS, 5),
234 &peergroup_shutdown_callback,
240 * Completion callback for shutdown
242 * @param cls the closure from GNUNET_STREAM_shutdown call
243 * @param operation the operation that was shutdown (SHUT_RD, SHUT_WR,
247 shutdown_completion (void *cls,
250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
251 "STREAM shutdown successful\n");
252 GNUNET_SCHEDULER_add_now (&do_close,
259 * Shutdown sockets gracefully
262 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
264 peer1.shutdown_handle = GNUNET_STREAM_shutdown (peer1.socket,
266 &shutdown_completion,
272 * Something went wrong and timed out. Kill everything and set error flag
275 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n");
278 result = GNUNET_SYSERR;
285 * The write completion function; called upon writing some data to stream or
288 * @param cls the closure from GNUNET_STREAM_write/read
289 * @param status the status of the stream at the time this function is called
290 * @param size the number of bytes read or written
293 write_completion (void *cls,
294 enum GNUNET_STREAM_Status status,
297 struct PeerData *peer=cls;
299 GNUNET_assert (GNUNET_STREAM_OK == status);
300 GNUNET_assert (size <= strlen (data));
301 peer->bytes_wrote += size;
303 if (peer->bytes_wrote < strlen(data)) /* Have more data to send */
305 GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
310 "Writing completed\n");
312 if (&peer1 == peer) /* Peer1 has finished writing; should read now */
314 peer->bytes_read = 0;
315 GNUNET_SCHEDULER_add_now (&stream_read_task, peer);
319 writing_success = GNUNET_YES;
320 if (GNUNET_YES == reading_success)
321 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
328 * Function executed after stream has been established
330 * @param cls the closure from GNUNET_STREAM_open
331 * @param socket socket to use to communicate with the other side (read/write)
334 stream_open_cb (void *cls,
335 struct GNUNET_STREAM_Socket *socket)
337 struct PeerData *peer=cls;
339 GNUNET_assert (&peer1 == peer);
340 GNUNET_assert (socket == peer1.socket);
341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342 "%s: Stream established from peer1\n",
343 GNUNET_i2s (&peer1.our_id));
344 peer->bytes_wrote = 0;
345 GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
352 * @param cls the closure from GNUNET_STREAM_write/read
353 * @param status the status of the stream at the time this function is called
354 * @param data traffic from the other side
355 * @param size the number of bytes available in data read
356 * @return number of bytes of processed from 'data' (any data remaining should be
357 * given to the next time the read processor is called).
360 input_processor (void *cls,
361 enum GNUNET_STREAM_Status status,
362 const void *input_data,
365 struct PeerData *peer;
367 peer = (struct PeerData *) cls;
369 if (GNUNET_STREAM_TIMEOUT == status)
371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
372 "Read operation timedout - reading again!\n");
373 GNUNET_assert (0 == size);
374 GNUNET_SCHEDULER_add_now (&stream_read_task, peer);
378 GNUNET_assert (GNUNET_STREAM_OK == status);
379 GNUNET_assert (size <= strlen (data));
380 GNUNET_assert (0 == strncmp ((const char *) data + peer->bytes_read,
381 (const char *) input_data,
383 peer->bytes_read += size;
385 if (peer->bytes_read < strlen (data))
387 GNUNET_SCHEDULER_add_now (&stream_read_task, peer);
391 if (&peer2 == peer) /* Peer2 has completed reading; should write */
393 peer->bytes_wrote = 0;
394 GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
396 else /* Peer1 has completed reading. End of tests */
398 reading_success = GNUNET_YES;
399 if (GNUNET_YES == writing_success)
400 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
408 * Functions of this type are called upon new stream connection from other peers
410 * @param cls the closure from GNUNET_STREAM_listen
411 * @param socket the socket representing the stream
412 * @param initiator the identity of the peer who wants to establish a stream
414 * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the
415 * stream (the socket will be invalid after the call)
418 stream_listen_cb (void *cls,
419 struct GNUNET_STREAM_Socket *socket,
420 const struct GNUNET_PeerIdentity *initiator)
422 GNUNET_assert (NULL != socket);
423 GNUNET_assert (NULL != initiator);
424 GNUNET_assert (socket != peer1.socket);
426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
427 "%s: Peer connected: %s\n",
428 GNUNET_i2s (&peer2.our_id),
429 GNUNET_i2s(initiator));
431 peer2.socket = socket;
432 peer2.bytes_read = 0;
433 GNUNET_SCHEDULER_add_now (&stream_read_task, &peer2);
439 * Listen success callback; connects a peer to stream as client
442 stream_connect (void)
444 peer1.socket = GNUNET_STREAM_open (d1->cfg,
445 &d2->id, /* Null for local peer? */
449 GNUNET_STREAM_OPTION_END);
450 GNUNET_assert (NULL != peer1.socket);
455 * Callback to be called when testing peer group is ready
458 * @param emsg NULL on success
461 peergroup_ready (void *cls, const char *emsg)
465 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
466 "Starting peer group failed: %s\n", emsg);
469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
470 "Peer group is now ready\n");
472 GNUNET_assert (2 == GNUNET_TESTING_daemons_running (pg));
474 d1 = GNUNET_TESTING_daemon_get (pg, 0);
475 GNUNET_assert (NULL != d1);
477 d2 = GNUNET_TESTING_daemon_get (pg, 1);
478 GNUNET_assert (NULL != d2);
480 GNUNET_TESTING_get_peer_identity (d1->cfg,
482 GNUNET_TESTING_get_peer_identity (d2->cfg,
484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
486 GNUNET_i2s (&peer1.our_id),
487 GNUNET_i2s (&d1->id));
488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
490 GNUNET_i2s (&peer2.our_id),
491 GNUNET_i2s (&d2->id));
493 peer2_listen_socket =
494 GNUNET_STREAM_listen (d2->cfg,
498 GNUNET_STREAM_OPTION_SIGNAL_LISTEN_SUCCESS,
500 GNUNET_STREAM_OPTION_END);
501 GNUNET_assert (NULL != peer2_listen_socket);
506 * Initialize framework and start test
509 run (void *cls, char *const *args, const char *cfgfile,
510 const struct GNUNET_CONFIGURATION_Handle *cfg)
512 struct GNUNET_TESTING_Host *hosts; /* FIXME: free hosts (DLL) */
514 GNUNET_log_setup ("test_stream_2peers",
518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
520 /* Duplicate the configuration */
521 config = GNUNET_CONFIGURATION_dup (cfg);
523 hosts = GNUNET_TESTING_hosts_load (config);
525 pg = GNUNET_TESTING_peergroup_start (config,
527 GNUNET_TIME_relative_multiply
528 (GNUNET_TIME_UNIT_SECONDS, 3),
533 GNUNET_assert (NULL != pg);
536 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
537 (GNUNET_TIME_UNIT_SECONDS, 40), &do_abort,
544 int main (int argc, char **argv)
548 char *argv2[] = { "test-stream-2peers",
550 "-c", "test_stream_local.conf",
553 struct GNUNET_GETOPT_CommandLineOption options[] = {
554 GNUNET_GETOPT_OPTION_END
558 GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
559 "test-stream-2peers", "nohelp", options, &run, NULL);
561 if (GNUNET_OK != ret)
563 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n",
567 if (GNUNET_SYSERR == result)
569 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n");
572 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test ok\n");