newline
[oweals/gnunet.git] / src / util / test_server.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 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 2, 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  * @file util/test_server.c
22  * @brief tests for server.c
23  */
24 #include "platform.h"
25 #include "gnunet_common.h"
26 #include "gnunet_scheduler_lib.h"
27 #include "gnunet_server_lib.h"
28 #include "gnunet_time_lib.h"
29
30 #define VERBOSE GNUNET_NO
31
32 #define PORT 12435
33
34 #define MY_TYPE 128
35 #define MY_TYPE2 129
36
37 static struct GNUNET_SERVER_Handle *server;
38
39 static struct GNUNET_SCHEDULER_Handle *sched;
40
41 static void
42 recv_fin_cb (void *cls,
43              struct GNUNET_SERVER_Client *client,
44              const struct GNUNET_MessageHeader *message)
45 {
46   int *ok = cls;
47   GNUNET_assert (2 == *ok);
48   GNUNET_SERVER_receive_done (client, GNUNET_OK);
49   *ok = 3;
50 }
51
52 struct SignalTimeoutContext
53 {
54   GNUNET_CONNECTION_Receiver cb;
55   void *cb_cls;
56 };
57
58
59 static void
60 signal_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
61 {
62   struct SignalTimeoutContext *stctx = cls;
63
64   stctx->cb (stctx->cb_cls, NULL, 0, NULL, 0, 0);
65   GNUNET_free (stctx);
66 }
67
68
69 static GNUNET_SCHEDULER_TaskIdentifier ti;
70
71
72 static void
73 my_receive (void *cls,
74             size_t max,
75             struct GNUNET_TIME_Relative timeout,
76             GNUNET_CONNECTION_Receiver receiver, void *receiver_cls)
77 {
78   int *ok = cls;
79   struct GNUNET_MessageHeader msg;
80   struct SignalTimeoutContext *stctx;
81   GNUNET_SCHEDULER_TaskIdentifier ret;
82
83   ret = GNUNET_SCHEDULER_NO_TASK;
84   switch (*ok)
85     {
86     case 1:
87       *ok = 2;                  /* report success */
88       msg.type = htons (MY_TYPE2);
89       msg.size = htons (sizeof (struct GNUNET_MessageHeader));
90       receiver (receiver_cls, &msg, sizeof (struct GNUNET_MessageHeader),
91                 NULL, 0, 0);
92       break;
93     case 3:
94       /* called after first receive instantly
95          produced a reply;
96          schedule receiver call with timeout
97          after timeout expires! */
98       *ok = 4;
99       stctx = GNUNET_malloc (sizeof (struct SignalTimeoutContext));
100       stctx->cb = receiver;
101       stctx->cb_cls = receiver_cls;
102       ret = GNUNET_SCHEDULER_add_delayed (sched,
103                                           timeout, &signal_timeout, stctx);
104       break;
105     default:
106       GNUNET_assert (0);
107     }
108   ti = ret;
109 }
110
111
112 static void
113 my_cancel (void *cls)
114 {
115   GNUNET_SCHEDULER_cancel (sched, ti);
116 }
117
118 static void *
119 my_transmit_ready_cb (void *cls,
120                       size_t size,
121                       struct GNUNET_TIME_Relative timeout,
122                       GNUNET_CONNECTION_TransmitReadyNotify notify,
123                       void *notify_cls)
124 {
125   static int non_null_addr;
126   int *ok = cls;
127   char buf[size];
128   struct GNUNET_MessageHeader msg;
129
130   GNUNET_assert (4 == *ok);
131   GNUNET_assert (size == sizeof (struct GNUNET_MessageHeader));
132   notify (notify_cls, size, buf);
133   msg.type = htons (MY_TYPE);
134   msg.size = htons (sizeof (struct GNUNET_MessageHeader));
135   GNUNET_assert (0 == memcmp (&msg, buf, size));
136   *ok = 5;                      /* report success */
137   return &non_null_addr;
138 }
139
140
141 static void
142 my_transmit_ready_cancel_cb (void *cls, void *ctx)
143 {
144   GNUNET_assert (0);
145 }
146
147
148 static int
149 my_check (void *cls)
150 {
151   return GNUNET_YES;
152 }
153
154
155 static void my_destroy (void *cls, int persist);
156
157
158 struct CopyContext
159 {
160   struct GNUNET_SERVER_Client *client;
161   struct GNUNET_MessageHeader *cpy;
162 };
163
164 static size_t
165 copy_msg (void *cls, size_t size, void *buf)
166 {
167   struct CopyContext *ctx = cls;
168   struct GNUNET_MessageHeader *cpy = ctx->cpy;
169   GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (cpy->size));
170   GNUNET_assert (size >= ntohs (cpy->size));
171   memcpy (buf, cpy, ntohs (cpy->size));
172   GNUNET_free (cpy);
173   GNUNET_free (ctx);
174   return sizeof (struct GNUNET_MessageHeader);
175 }
176
177
178 static void
179 recv_cb (void *cls,
180          struct GNUNET_SERVER_Client *argclient,
181          const struct GNUNET_MessageHeader *message)
182 {
183   struct GNUNET_SERVER_Client *client;
184   struct CopyContext *cc;
185   struct GNUNET_MessageHeader *cpy;
186
187   GNUNET_assert (argclient == NULL);
188   GNUNET_assert (sizeof (struct GNUNET_MessageHeader) ==
189                  ntohs (message->size));
190   GNUNET_assert (MY_TYPE == ntohs (message->type));
191   client = GNUNET_SERVER_connect_callback (server,
192                                            cls,
193                                            &my_receive,
194                                            &my_cancel,
195                                            &my_transmit_ready_cb,
196                                            &my_transmit_ready_cancel_cb,
197                                            &my_check, &my_destroy);
198   cc = GNUNET_malloc (sizeof (struct CopyContext));
199   cc->client = client;
200   cpy = GNUNET_malloc (ntohs (message->size));
201   memcpy (cpy, message, ntohs (message->size));
202   cc->cpy = cpy;
203   GNUNET_assert (NULL !=
204                  GNUNET_SERVER_notify_transmit_ready (client,
205                                                       ntohs (message->size),
206                                                       GNUNET_TIME_UNIT_SECONDS,
207                                                       &copy_msg, cc));
208   GNUNET_SERVER_client_drop (client);
209 }
210
211
212 static struct GNUNET_SERVER_MessageHandler handlers[] = {
213   {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
214   {&recv_fin_cb, NULL, MY_TYPE2, sizeof (struct GNUNET_MessageHeader)},
215   {NULL, NULL, 0, 0}
216 };
217
218
219 static void
220 my_destroy (void *cls, int persist)
221 {
222   int *ok = cls;
223   GNUNET_assert (5 == *ok);
224   *ok = 0;                      /* report success */
225   /* this will cause us to terminate */
226   GNUNET_SERVER_destroy (server);
227 }
228
229
230 static void
231 task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
232 {
233   struct sockaddr_in sa;
234   struct GNUNET_MessageHeader msg;
235   struct sockaddr * sap[2];
236   socklen_t slens[2];
237
238   sap[0] = (struct sockaddr*) &sa;
239   slens[0] = sizeof (sa);
240   sap[1] = NULL;
241   slens[1] = 0;
242   sched = tc->sched;
243   memset (&sa, 0, sizeof (sa));
244 #if HAVE_SOCKADDR_IN_SIN_LEN
245   sa.sin_len = sizeof (sa);
246 #endif
247   sa.sin_family = AF_INET;
248   sa.sin_port = htons (PORT);
249   server = GNUNET_SERVER_create (tc->sched,
250                                  NULL,
251                                  NULL,
252                                  sap,
253                                  slens,
254                                  1024,
255                                  GNUNET_TIME_relative_multiply
256                                  (GNUNET_TIME_UNIT_MILLISECONDS, 250),
257                                  GNUNET_NO);
258   GNUNET_assert (server != NULL);
259   handlers[0].callback_cls = cls;
260   handlers[1].callback_cls = cls;
261   GNUNET_SERVER_add_handlers (server, handlers);
262   msg.type = htons (MY_TYPE);
263   msg.size = htons (sizeof (struct GNUNET_MessageHeader));
264   GNUNET_SERVER_inject (server, NULL, &msg);
265   memset (&msg, 0, sizeof (struct GNUNET_MessageHeader));
266 }
267
268
269 /**
270  * Main method, starts scheduler with task1,
271  * checks that "ok" is correct at the end.
272  */
273 static int
274 check ()
275 {
276   int ok;
277
278   ok = 1;
279   GNUNET_SCHEDULER_run (&task, &ok);
280   return ok;
281 }
282
283
284 int
285 main (int argc, char *argv[])
286 {
287   int ret = 0;
288
289   GNUNET_log_setup ("test_server", "WARNING", NULL);
290   ret += check ();
291
292   return ret;
293 }
294
295 /* end of test_server.c */