e3df0b456472732ce95c02ae942517c46b1d0fd9
[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_Handle *server,
44              struct GNUNET_SERVER_Client *client,
45              const struct GNUNET_MessageHeader *message)
46 {
47   int *ok = cls;
48   GNUNET_assert (2 == *ok);
49   GNUNET_SERVER_receive_done (client, GNUNET_OK);
50   *ok = 3;
51 }
52
53 struct SignalTimeoutContext
54 {
55   GNUNET_NETWORK_Receiver cb;
56   void *cb_cls;
57 };
58
59
60 static void
61 signal_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
62 {
63   struct SignalTimeoutContext *stctx = cls;
64
65   stctx->cb (stctx->cb_cls, NULL, 0, NULL, 0, 0);
66   GNUNET_free (stctx);
67 }
68
69
70 static GNUNET_SCHEDULER_TaskIdentifier
71 my_receive (void *cls,
72             size_t max,
73             struct GNUNET_TIME_Relative timeout,
74             GNUNET_NETWORK_Receiver receiver, void *receiver_cls)
75 {
76   int *ok = cls;
77   struct GNUNET_MessageHeader msg;
78   struct SignalTimeoutContext *stctx;
79   GNUNET_SCHEDULER_TaskIdentifier ret;
80
81   ret = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
82   switch (*ok)
83     {
84     case 1:
85       *ok = 2;                  /* report success */
86       msg.type = htons (MY_TYPE2);
87       msg.size = htons (sizeof (msg));
88       receiver (receiver_cls, &msg, sizeof (msg), NULL, 0, 0);
89       break;
90     case 3:
91       /* called after first receive instantly
92          produced a reply;
93          schedule receiver call with timeout
94          after timeout expires! */
95       *ok = 4;
96       stctx = GNUNET_malloc (sizeof (struct SignalTimeoutContext));
97       stctx->cb = receiver;
98       stctx->cb_cls = receiver_cls;
99       ret = GNUNET_SCHEDULER_add_delayed (sched,
100                                           GNUNET_NO,
101                                           GNUNET_SCHEDULER_PRIORITY_KEEP,
102                                           GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
103                                           timeout, &signal_timeout, stctx);
104       break;
105     default:
106       GNUNET_assert (0);
107     }
108   return ret;
109 }
110
111
112 static void
113 my_cancel (void *cls, GNUNET_SCHEDULER_TaskIdentifier ti)
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_NETWORK_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 (msg));
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);
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_Handle *server,
181          struct GNUNET_SERVER_Client *argclient,
182          const struct GNUNET_MessageHeader *message)
183 {
184   struct GNUNET_SERVER_Client *client;
185   struct CopyContext *cc;
186   struct GNUNET_MessageHeader *cpy;
187
188   GNUNET_assert (argclient == NULL);
189   GNUNET_assert (sizeof (struct GNUNET_MessageHeader) ==
190                  ntohs (message->size));
191   GNUNET_assert (MY_TYPE == ntohs (message->type));
192   client = GNUNET_SERVER_connect_callback (server,
193                                            cls,
194                                            &my_receive,
195                                            &my_cancel,
196                                            &my_transmit_ready_cb,
197                                            &my_transmit_ready_cancel_cb,
198                                            &my_check, &my_destroy);
199   cc = GNUNET_malloc (sizeof (struct CopyContext));
200   cc->client = client;
201   cpy = GNUNET_malloc (ntohs (message->size));
202   memcpy (cpy, message, ntohs (message->size));
203   cc->cpy = cpy;
204   GNUNET_assert (NULL !=
205                  GNUNET_SERVER_notify_transmit_ready (client,
206                                                       ntohs (message->size),
207                                                       GNUNET_TIME_UNIT_SECONDS,
208                                                       &copy_msg, cc));
209   GNUNET_SERVER_client_drop (client);
210 }
211
212
213 static struct GNUNET_SERVER_MessageHandler handlers[] = {
214   {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
215   {&recv_fin_cb, NULL, MY_TYPE2, sizeof (struct GNUNET_MessageHeader)},
216   {NULL, NULL, 0, 0}
217 };
218
219
220 static void
221 my_destroy (void *cls)
222 {
223   int *ok = cls;
224   GNUNET_assert (5 == *ok);
225   *ok = 0;                      /* report success */
226   /* this will cause us to terminate */
227   GNUNET_SERVER_destroy (server);
228 }
229
230
231 static void
232 task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
233 {
234   struct sockaddr_in sa;
235   struct GNUNET_MessageHeader msg;
236
237   sched = tc->sched;
238   memset (&sa, 0, sizeof (sa));
239   sa.sin_family = AF_INET;
240   sa.sin_port = htons (PORT);
241   server = GNUNET_SERVER_create (tc->sched,
242                                  NULL,
243                                  NULL,
244                                  (const struct sockaddr *) &sa,
245                                  sizeof (sa),
246                                  1024,
247                                  GNUNET_TIME_relative_multiply
248                                  (GNUNET_TIME_UNIT_MILLISECONDS, 250),
249                                  GNUNET_NO);
250   GNUNET_assert (server != NULL);
251   handlers[0].callback_cls = cls;
252   handlers[1].callback_cls = cls;
253   GNUNET_SERVER_add_handlers (server, handlers);
254   msg.type = htons (MY_TYPE);
255   msg.size = htons (sizeof (msg));
256   GNUNET_SERVER_inject (server, NULL, &msg);
257   memset (&msg, 0, sizeof (msg));
258 }
259
260
261 /**
262  * Main method, starts scheduler with task1,
263  * checks that "ok" is correct at the end.
264  */
265 static int
266 check ()
267 {
268   int ok;
269
270   ok = 1;
271   GNUNET_SCHEDULER_run (&task, &ok);
272   return ok;
273 }
274
275
276 int
277 main (int argc, char *argv[])
278 {
279   int ret = 0;
280
281   GNUNET_log_setup ("test_server", "WARNING", NULL);
282   ret += check ();
283
284   return ret;
285 }
286
287 /* end of test_server.c */