Missing declarations
[oweals/gnunet.git] / src / stream / test_stream_sequence_wraparound.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_sequence_wraparound.c
23  * @brief test cases for sequence wrap around situations during data transfer
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_stream_lib.h"
32 #include "gnunet_testing_lib-new.h"
33
34 /**
35  * Generic logging shorthand
36  */
37 #define LOG(kind, ...)                         \
38   GNUNET_log (kind, __VA_ARGS__);
39
40 /**
41  * Relative seconds shorthand
42  */
43 #define TIME_REL_SECS(sec) \
44   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
45
46 /**
47  * Structure for holding peer's sockets and IO Handles
48  */
49 struct PeerData
50 {
51   /**
52    * Peer's stream socket
53    */
54   struct GNUNET_STREAM_Socket *socket;
55
56   /**
57    * Peer's io write handle
58    */
59   struct GNUNET_STREAM_IOWriteHandle *io_write_handle;
60
61   /**
62    * Peer's io read handle
63    */
64   struct GNUNET_STREAM_IOReadHandle *io_read_handle;
65
66   /**
67    * Bytes the peer has written
68    */
69   unsigned int bytes_wrote;
70
71   /**
72    * Byte the peer has read
73    */
74   unsigned int bytes_read;
75 };
76
77 static struct PeerData peer1;
78 static struct PeerData peer2;
79 static struct GNUNET_STREAM_ListenSocket *peer2_listen_socket;
80 static const struct GNUNET_CONFIGURATION_Handle *config;
81 static struct GNUNET_TESTING_Peer *self;
82 static struct GNUNET_PeerIdentity self_id;
83
84 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
85 static GNUNET_SCHEDULER_TaskIdentifier read_task;
86 static GNUNET_SCHEDULER_TaskIdentifier write_task;
87
88 #define DATA_SIZE 65536      /* 64KB */
89 static uint32_t data[DATA_SIZE / 4];     /* 64KB array */
90 static int result;
91
92 /**
93  * Shutdown nicely
94  */
95 static void
96 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
97 {
98   GNUNET_STREAM_close (peer1.socket);
99   if (NULL != peer2.socket)
100     GNUNET_STREAM_close (peer2.socket);
101   if (NULL != peer2_listen_socket)
102     GNUNET_STREAM_listen_close (peer2_listen_socket); /* Close listen socket */
103   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n");
104   if (0 != abort_task)
105   {
106     GNUNET_SCHEDULER_cancel (abort_task);
107   }
108 }
109
110
111 /**
112  * Something went wrong and timed out. Kill everything and set error flag
113  */
114 static void
115 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
116 {
117   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n");
118   if (GNUNET_SCHEDULER_NO_TASK != read_task)
119     {
120       GNUNET_SCHEDULER_cancel (read_task);
121     }
122   result = GNUNET_SYSERR;
123   abort_task = 0;
124   do_shutdown (cls, tc);
125 }
126
127
128 /**
129  * The write completion function; called upon writing some data to stream or
130  * upon error
131  *
132  * @param cls the closure from GNUNET_STREAM_write/read
133  * @param status the status of the stream at the time this function is called
134  * @param size the number of bytes read or written
135  */
136 static void 
137 write_completion (void *cls,
138                   enum GNUNET_STREAM_Status status,
139                   size_t size)
140 {
141   struct PeerData *peer;
142
143   peer = (struct PeerData *) cls;
144   GNUNET_assert (GNUNET_STREAM_OK == status);
145   GNUNET_assert (size <= DATA_SIZE);
146   peer->bytes_wrote += size;
147
148   if (peer->bytes_wrote < DATA_SIZE) /* Have more data to send */
149     {
150       peer->io_write_handle =
151         GNUNET_STREAM_write (peer->socket,
152                              ((void *) data) + peer->bytes_wrote,
153                              DATA_SIZE - peer->bytes_wrote,
154                              GNUNET_TIME_relative_multiply
155                              (GNUNET_TIME_UNIT_SECONDS, 5),
156                              &write_completion,
157                              cls);
158       GNUNET_assert (NULL != peer->io_write_handle);
159     }
160   else
161     {
162       LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing successfully finished\n");
163       result = GNUNET_OK;
164       GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
165     }
166 }
167
168
169 /**
170  * Task for calling STREAM_write with a chunk of random data
171  *
172  * @param cls the peer data entity
173  * @param tc the task context
174  */
175 static void
176 stream_write_task (void *cls,
177                    const struct GNUNET_SCHEDULER_TaskContext *tc)
178 {
179   struct PeerData *peer=cls;
180   unsigned int count;
181
182   write_task = GNUNET_SCHEDULER_NO_TASK;
183   for (count=0; count < DATA_SIZE / 4; count++)
184     {
185       data[count]=GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
186                                             UINT32_MAX);
187     }
188   LOG (GNUNET_ERROR_TYPE_DEBUG, "Generation of random data complete\n");
189   peer->io_write_handle = GNUNET_STREAM_write (peer->socket,
190                                                data,
191                                                DATA_SIZE,
192                                                GNUNET_TIME_relative_multiply
193                                                (GNUNET_TIME_UNIT_SECONDS, 10),
194                                                &write_completion,
195                                                peer);
196   GNUNET_assert (NULL != peer->io_write_handle);
197 }
198
199
200 /**
201  * Function executed after stream has been established
202  *
203  * @param cls the closure from GNUNET_STREAM_open
204  * @param socket socket to use to communicate with the other side (read/write)
205  */
206 static void 
207 stream_open_cb (void *cls,
208                 struct GNUNET_STREAM_Socket *socket)
209 {
210   struct PeerData *peer;
211
212   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stream established from peer1\n");
213   peer = (struct PeerData *) cls;
214   peer->bytes_wrote = 0;
215   GNUNET_assert (socket == peer1.socket);
216   GNUNET_assert (socket == peer->socket);
217   write_task = GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
218 }
219
220
221 /**
222  * Scheduler call back; to be executed when a new stream is connected
223  * Called from listen connect for peer2
224  */
225 static void
226 stream_read_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
227
228
229 /**
230  * Input processor
231  *
232  * @param cls peer2
233  * @param status the status of the stream at the time this function is called
234  * @param data traffic from the other side
235  * @param size the number of bytes available in data read 
236  * @return number of bytes of processed from 'data' (any data remaining should be
237  *         given to the next time the read processor is called).
238  */
239 static size_t
240 input_processor (void *cls,
241                  enum GNUNET_STREAM_Status status,
242                  const void *input_data,
243                  size_t size)
244 {
245   struct PeerData *peer = cls;
246
247   GNUNET_assert (GNUNET_STREAM_OK == status);
248   GNUNET_assert (&peer2 == peer);
249   GNUNET_assert (size < DATA_SIZE);
250   GNUNET_assert (0 == memcmp (((void *)data ) + peer->bytes_read, 
251                               input_data, size));
252   peer->bytes_read += size;
253   
254   if (peer->bytes_read < DATA_SIZE)
255   {
256     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == read_task);
257     read_task = GNUNET_SCHEDULER_add_now (&stream_read_task, &peer2);
258   }
259   else 
260   {
261     /* Peer2 has completed reading*/
262     LOG (GNUNET_ERROR_TYPE_DEBUG, "Reading finished successfully\n");
263   } 
264   return size;
265 }
266
267   
268 /**
269  * Scheduler call back; to be executed when a new stream is connected
270  * Called from listen connect for peer2
271  */
272 static void
273 stream_read_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
274 {
275   struct PeerData *peer = cls;
276
277   read_task = GNUNET_SCHEDULER_NO_TASK;
278   GNUNET_assert (&peer2 == peer);  
279   peer->io_read_handle =
280     GNUNET_STREAM_read (peer->socket,
281                         GNUNET_TIME_relative_multiply
282                         (GNUNET_TIME_UNIT_SECONDS, 10),
283                         &input_processor,
284                         peer);
285   GNUNET_assert (NULL != peer->io_read_handle);
286 }
287
288
289 /**
290  * Functions of this type are called upon new stream connection from other peers
291  *
292  * @param cls the closure from GNUNET_STREAM_listen
293  * @param socket the socket representing the stream
294  * @param initiator the identity of the peer who wants to establish a stream
295  *            with us
296  * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the
297  *             stream (the socket will be invalid after the call)
298  */
299 static int
300 stream_listen_cb (void *cls,
301            struct GNUNET_STREAM_Socket *socket,
302            const struct GNUNET_PeerIdentity *initiator)
303 {
304   GNUNET_assert (NULL != socket);
305   GNUNET_assert (socket != peer1.socket);
306   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
307               "Peer connected: %s\n", GNUNET_i2s(initiator));
308   peer2.socket = socket;
309   peer2.bytes_read = 0;
310   read_task = GNUNET_SCHEDULER_add_now (&stream_read_task, &peer2);
311   return GNUNET_OK;
312 }
313
314
315 /**
316  * Listen success callback; connects a peer to stream as client
317  */
318 static void
319 stream_connect (void)
320 {
321   peer1.socket = 
322     GNUNET_STREAM_open (config,
323                         &self_id,         /* Null for local peer? */
324                         10,           /* App port */
325                         &stream_open_cb,
326                         &peer1,
327                         GNUNET_STREAM_OPTION_TESTING_SET_WRITE_SEQUENCE_NUMBER,
328                         UINT32_MAX - GNUNET_CRYPTO_random_u32
329                         (GNUNET_CRYPTO_QUALITY_WEAK, 64),
330                         GNUNET_STREAM_OPTION_MAX_PAYLOAD_SIZE, 500,
331                         GNUNET_STREAM_OPTION_END);
332   GNUNET_assert (NULL != peer1.socket);
333 }
334
335
336 /**
337  * Initialize framework and start test
338  */
339 static void
340 run (void *cls,
341      const struct GNUNET_CONFIGURATION_Handle *cfg,
342      struct GNUNET_TESTING_Peer *peer)
343 {
344   config = cfg;
345   self = peer;
346   (void) GNUNET_TESTING_peer_get_identity (peer, &self_id);
347   peer2_listen_socket = 
348     GNUNET_STREAM_listen (config,
349                           10, /* App port */
350                           &stream_listen_cb,
351                           NULL,
352                           GNUNET_STREAM_OPTION_LISTEN_TIMEOUT,
353                           60 * 1000,
354                           GNUNET_STREAM_OPTION_SIGNAL_LISTEN_SUCCESS,
355                           &stream_connect,
356                           GNUNET_STREAM_OPTION_END);
357   GNUNET_assert (NULL != peer2_listen_socket);
358   abort_task =
359     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
360                                   (GNUNET_TIME_UNIT_SECONDS, 100), &do_abort,
361                                   NULL);
362 }
363
364
365 /**
366  * Main function
367  */
368 int main (int argc, char **argv)
369 {
370   if (0 != GNUNET_TESTING_peer_run ("test_stream_sequence_wraparound",
371                                     "test_stream_local.conf",
372                                     &run, NULL))
373     return 1;
374   return (GNUNET_SYSERR == result) ? 1 : 0;
375 }
376
377 /* end of test_stream_sequence_wraparound.c */