regex profiler cleanup
[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-new.h"
34
35 /**
36  * Relative seconds shorthand
37  */
38 #define TIME_REL_SECS(sec) \
39   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
40
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    * Bytes the peer has written
64    */
65   unsigned int bytes_wrote;
66
67   /**
68    * Byte the peer has read
69    */
70   unsigned int bytes_read;
71 };
72
73 static struct PeerData peer1;
74 static struct PeerData peer2;
75 static struct GNUNET_STREAM_ListenSocket *peer2_listen_socket;
76 static const struct GNUNET_CONFIGURATION_Handle *config;
77 static struct GNUNET_TESTING_Peer *self;
78 static struct GNUNET_PeerIdentity self_id;
79
80 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
81
82 static char *data = "ABCD";
83 static int result;
84
85 static int writing_success;
86 static int reading_success;
87
88
89 /**
90  * Input processor
91  *
92  * @param cls the closure from GNUNET_STREAM_write/read
93  * @param status the status of the stream at the time this function is called
94  * @param data traffic from the other side
95  * @param size the number of bytes available in data read 
96  * @return number of bytes of processed from 'data' (any data remaining should be
97  *         given to the next time the read processor is called).
98  */
99 static size_t
100 input_processor (void *cls,
101                  enum GNUNET_STREAM_Status status,
102                  const void *input_data,
103                  size_t size);
104
105 /**
106  * Task for calling STREAM_read
107  *
108  * @param cls the peer data entity
109  * @param tc the task context
110  */
111 static void
112 stream_read_task (void *cls,
113                   const struct GNUNET_SCHEDULER_TaskContext *tc)
114 {
115   struct PeerData *peer = cls;
116   
117   peer->io_read_handle = GNUNET_STREAM_read (peer->socket,
118                                              GNUNET_TIME_relative_multiply
119                                              (GNUNET_TIME_UNIT_SECONDS, 5),
120                                              &input_processor,
121                                              peer);
122   GNUNET_assert (NULL != peer->io_read_handle);
123 }
124
125
126 /**
127  * The write completion function; called upon writing some data to stream or
128  * upon error
129  *
130  * @param cls the closure from GNUNET_STREAM_write/read
131  * @param status the status of the stream at the time this function is called
132  * @param size the number of bytes read or written
133  */
134 static void 
135 write_completion (void *cls,
136                   enum GNUNET_STREAM_Status status,
137                   size_t size);
138
139
140 /**
141  * Task for calling STREAM_write
142  *
143  * @param cls the peer data entity
144  * @param tc the task context
145  */
146 static void
147 stream_write_task (void *cls,
148                    const struct GNUNET_SCHEDULER_TaskContext *tc)
149 {
150   struct PeerData *peer = cls;
151   
152   peer->io_write_handle = 
153     GNUNET_STREAM_write (peer->socket,
154                          (void *) data,
155                          strlen(data) - peer->bytes_wrote,
156                          GNUNET_TIME_relative_multiply
157                          (GNUNET_TIME_UNIT_SECONDS, 5),
158                          &write_completion,
159                          peer);
160  
161   GNUNET_assert (NULL != peer->io_write_handle);
162  }
163
164
165 /**
166  * Shutdown nicely
167  */
168 static void
169 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
170 {
171   if (NULL != peer1.socket)
172     GNUNET_STREAM_close (peer1.socket);
173   if (NULL != peer2.socket)
174     GNUNET_STREAM_close (peer2.socket);
175   if (NULL != peer2_listen_socket)
176     GNUNET_STREAM_listen_close (peer2_listen_socket);
177   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n");
178   if (0 != abort_task)
179   {
180     GNUNET_SCHEDULER_cancel (abort_task);
181   }
182 }
183
184
185 /**
186  * Something went wrong and timed out. Kill everything and set error flag
187  */
188 static void
189 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
190 {
191   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n");
192   result = GNUNET_SYSERR;
193   abort_task = 0;
194   do_shutdown (cls, tc);
195 }
196
197
198 /**
199  * The write completion function; called upon writing some data to stream or
200  * upon error
201  *
202  * @param cls the closure from GNUNET_STREAM_write/read
203  * @param status the status of the stream at the time this function is called
204  * @param size the number of bytes read or written
205  */
206 static void 
207 write_completion (void *cls,
208                   enum GNUNET_STREAM_Status status,
209                   size_t size)
210 {
211   struct PeerData *peer=cls;
212
213   GNUNET_assert (GNUNET_STREAM_OK == status);
214   GNUNET_assert (size <= strlen (data));
215   peer->bytes_wrote += size;
216   if (peer->bytes_wrote < strlen(data)) /* Have more data to send */
217     {
218       GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
219     }
220   else
221     {
222       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
223                   "Writing completed\n");
224       if (&peer1 == peer)  /* Peer1 has finished writing; should read now */
225         {
226           peer->bytes_read = 0;
227           GNUNET_SCHEDULER_add_now (&stream_read_task, peer);
228         }
229       else
230         {
231           writing_success = GNUNET_YES;
232           if (GNUNET_YES == reading_success)
233             GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
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=cls;
250
251   GNUNET_assert (&peer1 == peer);
252   GNUNET_assert (socket == peer1.socket);
253   GNUNET_assert (socket == peer->socket);
254   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stream established from peer1\n");
255   peer->bytes_wrote = 0;
256   GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
257 }
258
259
260 /**
261  * Input processor
262  *
263  * @param cls the closure from GNUNET_STREAM_write/read
264  * @param status the status of the stream at the time this function is called
265  * @param data traffic from the other side
266  * @param size the number of bytes available in data read 
267  * @return number of bytes of processed from 'data' (any data remaining should be
268  *         given to the next time the read processor is called).
269  */
270 static size_t
271 input_processor (void *cls,
272                  enum GNUNET_STREAM_Status status,
273                  const void *input_data,
274                  size_t size)
275 {
276   struct PeerData *peer = cls;
277
278   GNUNET_assert (GNUNET_STREAM_OK == status);
279   GNUNET_assert (size <= strlen (data));
280   GNUNET_assert (0 == strncmp ((const char *) data + peer->bytes_read, 
281                                (const char *) input_data,
282                                size));
283   peer->bytes_read += size;  
284   if (peer->bytes_read < strlen (data))
285     {
286       GNUNET_SCHEDULER_add_now (&stream_read_task, peer);
287     }
288   else 
289     {
290       if (&peer2 == peer)    /* Peer2 has completed reading; should write */
291         {
292           peer->bytes_wrote = 0;
293           GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
294         }
295       else                      /* Peer1 has completed reading. End of tests */
296         {
297           reading_success = GNUNET_YES;
298           if (GNUNET_YES == writing_success)
299             GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
300         }
301     } 
302   return size;
303 }
304
305   
306 /**
307  * Functions of this type are called upon new stream connection from other peers
308  *
309  * @param cls the PeerData of peer2
310  * @param socket the socket representing the stream
311  * @param initiator the identity of the peer who wants to establish a stream
312  *            with us
313  * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the
314  *             stream (the socket will be invalid after the call)
315  */
316 static int
317 stream_listen_cb (void *cls,
318            struct GNUNET_STREAM_Socket *socket,
319            const struct GNUNET_PeerIdentity *initiator)
320 {
321   struct PeerData *peer=cls;
322
323   if ((NULL == socket) || (NULL == initiator))
324   {
325     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Binding error\n");
326     if (GNUNET_SCHEDULER_NO_TASK != abort_task)
327       GNUNET_SCHEDULER_cancel (abort_task);
328     abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
329     return GNUNET_OK;
330   }
331   GNUNET_assert (NULL != socket);
332   GNUNET_assert (socket != peer1.socket);
333   GNUNET_assert (&peer2 == peer);
334   GNUNET_assert (0 == memcmp (&self_id,
335                               initiator,
336                               sizeof (struct GNUNET_PeerIdentity)));
337   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338               "Peer connected: %s\n", GNUNET_i2s(initiator));
339   peer->socket = socket;
340   peer->bytes_read = 0;
341   GNUNET_SCHEDULER_add_now (&stream_read_task, &peer2);
342   return GNUNET_OK;
343 }
344
345
346 /**
347  * Listen success callback; connects a peer to stream as client
348  */
349 static void
350 stream_connect (void)
351 {
352   peer1.socket = GNUNET_STREAM_open (config,
353                                      &self_id,
354                                      10,           /* App port */
355                                      &stream_open_cb,
356                                      &peer1,
357                                      GNUNET_STREAM_OPTION_END);
358   GNUNET_assert (NULL != peer1.socket);
359 }
360
361
362 /**
363  * Initialize framework and start test
364  */
365 static void
366 run (void *cls,
367      const struct GNUNET_CONFIGURATION_Handle *cfg,
368      struct GNUNET_TESTING_Peer *peer)
369 {
370   config = cfg;
371   self = peer;
372   GNUNET_TESTING_peer_get_identity (peer, &self_id);
373   peer2_listen_socket = 
374     GNUNET_STREAM_listen (config,
375                           10, /* App port */
376                           &stream_listen_cb,
377                           &peer2,
378                           GNUNET_STREAM_OPTION_SIGNAL_LISTEN_SUCCESS,
379                           &stream_connect,
380                           GNUNET_STREAM_OPTION_END);
381   GNUNET_assert (NULL != peer2_listen_socket);
382   abort_task =
383     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
384                                   (GNUNET_TIME_UNIT_SECONDS, 30), &do_abort,
385                                   NULL);
386 }
387
388 /**
389  * Main function
390  */
391 int main (int argc, char **argv)
392 {
393   if (0 != GNUNET_TESTING_peer_run ("test_stream_local",
394                                     "test_stream_local.conf",
395                                     &run, NULL))
396     return 1;
397   return (GNUNET_SYSERR == result) ? 1 : 0;
398 }
399
400 /* end of test_stream_local.c */