added shutdown call in testcase
[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 #include <sys/socket.h>         /* For SHUT_RD, SHUT_WR */
29
30 #include "platform.h"
31 #include "gnunet_util_lib.h"
32 #include "gnunet_mesh_service.h"
33 #include "gnunet_stream_lib.h"
34
35 #define VERBOSE 1
36
37 static struct GNUNET_OS_Process *arm_pid;
38 static struct GNUNET_STREAM_Socket *peer1_socket;
39 static struct GNUNET_STREAM_ListenSocket *peer2_listen_socket;
40 static struct GNUNET_STREAM_Socket *peer2_socket;
41
42 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
43 static GNUNET_SCHEDULER_TaskIdentifier test_task;
44 static GNUNET_SCHEDULER_TaskIdentifier read_task;
45
46 static GNUNET_STREAM_IOHandle *peer1_IOHandle;
47 static GNUNET_STREAM_IOHandle *peer2_IOHandle;
48
49 static char *data = "ABCD";
50 static unsigned int data_pointer;
51 static unsigned int read_pointer;
52 static int result
53
54 static int test1_success_counter;
55
56
57 /**
58  * Shutdown nicely
59  */
60 static void
61 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
62 {
63   GNUNET_STREAM_close (peer1_socket);
64   GNUNET_STREAM_close (peer2_socket);
65   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n");
66   if (0 != abort_task)
67   {
68     GNUNET_SCHEDULER_cancel (abort_task);
69   }
70   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: arm\n");
71   if (0 != GNUNET_OS_process_kill (arm_pid, SIGTERM))
72   {
73     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
74   }
75   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Wait\n");
76   GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (arm_pid));
77   GNUNET_OS_process_close (arm_pid);
78 }
79
80
81 /**
82  * Something went wrong and timed out. Kill everything and set error flag
83  */
84 static void
85 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
86 {
87   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n");
88   if (0 != test_task)
89   {
90     GNUNET_SCHEDULER_cancel (test_task);
91   }
92   if (0 != read_task)
93     {
94       GNUNET_SCHEDULER_cancel (read_task);
95     }
96   result = GNUNET_SYSERR;
97   abort_task = 0;
98   do_shutdown (cls, tc);
99 }
100
101
102 /**
103  * The write completion function; called upon writing some data to stream or
104  * upon error
105  *
106  * @param cls the closure from GNUNET_STREAM_write/read
107  * @param status the status of the stream at the time this function is called
108  * @param size the number of bytes read or written
109  */
110 void write_completion (void *cls,
111                        enum GNUNET_STREAM_Status status,
112                        size_t size)
113 {
114
115   if (3 == test1_success_counter) /* Called for peer2's write operation */
116     {
117       /* peer1 has shutdown reading */
118       GNUNET_assert (GNUNET_STREAM_SHUTDOWN == status);
119       GNUNET_assert (0 == size);
120       test1_success_counter ++;
121       
122       GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
123     }
124   GNUNET_assert (GNUNET_STREAM_OK == status);
125   if (data_pointer + size != strlen(data)) /* Have more data to send */
126     {
127       data_pointer += size;
128       peer1_IOHandle = GNUNET_STREAM_write (peer1_socket,
129                                             (void *) data,
130                                             strlen(data) - data_pointer,
131                                             GNUNET_TIME_relative_multiply
132                                             (GNUNET_TIME_UNIT_SECONDS, 5),
133                                             &write_completion,
134                                             NULL);
135       GNUNET_assert (NULL != peer1_IOHandle);
136     }
137   else{                         /* Close peer1 socket */
138     test1_success_counter++;
139     GNUNET_STREAM_shutdown (peer1_socket, SHUT_RDWR);
140   }
141 }
142
143
144 /**
145  * Function executed after stream has been established
146  *
147  * @param cls the closure from GNUNET_STREAM_open
148  * @param socket socket to use to communicate with the other side (read/write)
149  */
150 static void 
151 stream_open_cb (void *cls,
152                 struct GNUNET_STREAM_Socket
153                 *socket)
154 {
155   data_pointer = 0;
156   GNUNET_assert (socket == peer1_socket);
157   peer1_IOHandle = GNUNET_STREAM_write (socket, /* socket */
158                                         (void *) data, /* data */
159                                         strlen(data),
160                                         GNUNET_TIME_relative_multiply
161                                         (GNUNET_TIME_UNIT_SECONDS, 5),
162                                         &write_completion,
163                                         NULL);
164   GNUNET_assert (NULL != peer1_IOHandle);     
165   
166 }
167
168
169 /**
170  * Input processor
171  *
172  * @param cls the closure from GNUNET_STREAM_write/read
173  * @param status the status of the stream at the time this function is called
174  * @param data traffic from the other side
175  * @param size the number of bytes available in data read 
176  * @return number of bytes of processed from 'data' (any data remaining should be
177  *         given to the next time the read processor is called).
178  */
179 static size_t
180 input_processor (void *cls,
181                  enum GNUNET_STREAM_Status status,
182                  const void *input_data,
183                  size_t size)
184 {
185
186   if (2 == test1_success_counter)
187     {
188       GNUNET_assert (GNUNET_STREAM_SHUTDOWN == status);
189       GNUNET_assert (0 == size);
190       test1_success_counter ++;
191       /* Now this should result in STREAM_SHUTDOWN */
192       peer2_IOHandle = GNUNET_STREAM_write (peer2_socket,
193                                             (void *) data,
194                                             strlen(data),
195                                             GNUNET_TIME_relative_multiply
196                                             (GNUNET_TIME_UNIT_SECONDS, 5),
197                                             &write_completion,
198                                             (void *) peer2_socket);
199                                             
200       return 0;
201     }
202
203   GNUNET_assert (GNUNET_STERAM_OK == status);
204   GNUNET_assert (size < strlen (data));
205   GNUNET_assert (strncmp ((const char *) data, 
206                           (const char *) input_data,
207                           size));
208   read_pointer += size;
209
210   if (read_pointer < strlen (data))
211     {
212       peer2_IOHandle = GNUNET_STREAM_read ((struct GNUNET_STREAM_Socket *) cls,
213                                        GNUNET_TIME_relative_multiply
214                                        (GNUNET_TIME_UNIT_SECONDS, 5),
215                                        &input_processor,
216                                        NULL);
217       GNUNET_assert (NULL != peer2_IOHandle);
218     }
219   else {
220     test1_success_counter ++;
221     /* This time should the read status should be STERAM_SHUTDOWN */
222     peer2_IOHandle = GNUNET_STREAM_read ((struct GNUNET_STREAM_Socket *) cls,
223                                          GNUNET_TIME_relative_multiply
224                                          (GNUNET_TIME_UNIT_SECONDS, 5),
225                                          &input_processor,
226                                          NULL);
227
228
229   }
230         
231   return size;
232 }
233
234
235 /**
236  * Scheduler call back; to be executed when a new stream is connected
237  */
238 static void
239 stream_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
240 {
241   read_task = GNUNET_SCHEDULER_NO_TASK;
242   GNUNET_assert (NULL != cls);
243   read_pointer = 0;
244   GNUNET_STREAM_listen_close (peer2_listen_socket); /* Close listen socket */
245   peer2_IOHandle = GNUNET_STREAM_read ((struct GNUNET_STREAM_Socket *) cls,
246                                        GNUNET_TIME_relative_multiply
247                                        (GNUNET_TIME_UNIT_SECONDS, 5),
248                                        &input_processor,
249                                        NULL);
250   GNUNET_assert (NULL != peer2_IOHandle);
251 }
252
253
254 /**
255  * Functions of this type are called upon new stream connection from other peers
256  *
257  * @param cls the closure from GNUNET_STREAM_listen
258  * @param socket the socket representing the stream
259  * @param initiator the identity of the peer who wants to establish a stream
260  *            with us
261  * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the
262  *             stream (the socket will be invalid after the call)
263  */
264 static int
265 stream_listen_cb (void *cls,
266            struct GNUNET_STREAM_Socket *socket,
267            const struct GNUNET_PeerIdentity *initiator)
268 {
269   GNUNET_assert (NULL != socket);
270   GNUNET_assert (NULL == initiator);   /* Local peer=NULL? */
271   GNUNET_assert (socket != peer1_socket);
272
273   peer2_socket = socket;
274   read_task = GNUNET_SCHEDULER_add_now (&stream_read, (void *) socket);
275   return GNUNET_OK;
276 }
277
278
279 /**
280  * Testing function
281  */
282 static void
283 test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
284 {
285   test_task = GNUNET_SCHEDULER_NO_TASK;
286   test1_success_counter = 0;
287   /* Connect to stream library */
288   peer1_socket = GNUNET_STREAM_open (NULL,         /* Null for local peer? */
289                                      10,           /* App port */
290                                      open_cb);
291   GNUNET_assert (NULL != peer1_socket);
292   peer2_listen_socket = GNUNET_STREAM_listen (10 /* App port */
293                                               &stream_listen_cb,
294                                               NULL);
295   GNUNET_assert (NULL != peer2_listen_socket);
296                   
297 }
298
299 /**
300  * Initialize framework and start test
301  */
302 static void
303 run (void *cls, char *const *args, const char *cfgfile,
304      const struct GNUNET_CONFIGURATION_Handle *cfg)
305 {
306    GNUNET_log_setup ("test_stream_local",
307 #if VERBOSE
308                     "DEBUG",
309 #else
310                     "WARNING",
311 #endif
312                     NULL);
313    arm_pid =
314      GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
315                               "gnunet-service-arm",
316 #if VERBOSE_ARM
317                               "-L", "DEBUG",
318 #endif
319                               "-c", "test_stream_local.conf", NULL);
320
321    abort_task =
322      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
323                                    (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort,
324                                     NULL);
325
326    test_task = GNUNET_SCHEDULER_add_now (&test, (void *) cfg);
327
328 }
329
330 /**
331  * Main function
332  */
333 int main (int argc, char **argv)
334 {
335   int ret;
336
337   char *const argv2[] = { "test-stream-local",
338                           "-c", "test_stream.conf",
339 #if VERBOSE
340                           "-L", "DEBUG",
341 #endif
342                           NULL
343   };
344   
345   struct GNUNET_GETOPT_CommandLineOption options[] = {
346     GNUNET_GETOPT_OPTION_END
347   };
348   
349   ret =
350       GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
351                           "test-stream-local", "nohelp", options, &run, NULL);
352
353   if (GNUNET_OK != ret)
354   {
355     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n",
356                 ret);
357     return 1;
358   }
359   if (GNUNET_SYSERR == result)
360   {
361     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n");
362     return 1;
363   }
364   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test ok\n");
365   return 0;
366 }