eadc03568032485f9321b840b95898ac0a949914
[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), NULL, 0, 0);
91       break;
92     case 3:
93       /* called after first receive instantly
94          produced a reply;
95          schedule receiver call with timeout
96          after timeout expires! */
97       *ok = 4;
98       stctx = GNUNET_malloc (sizeof (struct SignalTimeoutContext));
99       stctx->cb = receiver;
100       stctx->cb_cls = receiver_cls;
101       ret = GNUNET_SCHEDULER_add_delayed (sched,
102                                           GNUNET_NO,
103                                           GNUNET_SCHEDULER_PRIORITY_KEEP,
104                                           GNUNET_SCHEDULER_NO_TASK,
105                                           timeout, &signal_timeout, stctx);
106       break;
107     default:
108       GNUNET_assert (0);
109     }
110   ti = ret;
111 }
112
113
114 static void
115 my_cancel (void *cls)
116 {
117   GNUNET_SCHEDULER_cancel (sched, ti);
118 }
119
120 static void *
121 my_transmit_ready_cb (void *cls,
122                       size_t size,
123                       struct GNUNET_TIME_Relative timeout,
124                       GNUNET_CONNECTION_TransmitReadyNotify notify,
125                       void *notify_cls)
126 {
127   static int non_null_addr;
128   int *ok = cls;
129   char buf[size];
130   struct GNUNET_MessageHeader msg;
131
132   GNUNET_assert (4 == *ok);
133   GNUNET_assert (size == sizeof (struct GNUNET_MessageHeader));
134   notify (notify_cls, size, buf);
135   msg.type = htons (MY_TYPE);
136   msg.size = htons (sizeof (struct GNUNET_MessageHeader));
137   GNUNET_assert (0 == memcmp (&msg, buf, size));
138   *ok = 5;                      /* report success */
139   return &non_null_addr;
140 }
141
142
143 static void
144 my_transmit_ready_cancel_cb (void *cls, void *ctx)
145 {
146   GNUNET_assert (0);
147 }
148
149
150 static int
151 my_check (void *cls)
152 {
153   return GNUNET_YES;
154 }
155
156
157 static void my_destroy (void *cls);
158
159
160 struct CopyContext
161 {
162   struct GNUNET_SERVER_Client *client;
163   struct GNUNET_MessageHeader *cpy;
164 };
165
166 static size_t
167 copy_msg (void *cls, size_t size, void *buf)
168 {
169   struct CopyContext *ctx = cls;
170   struct GNUNET_MessageHeader *cpy = ctx->cpy;
171   GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (cpy->size));
172   GNUNET_assert (size >= ntohs (cpy->size));
173   memcpy (buf, cpy, ntohs (cpy->size));
174   GNUNET_free (cpy);
175   GNUNET_free (ctx);
176   return sizeof (struct GNUNET_MessageHeader);
177 }
178
179
180 static void
181 recv_cb (void *cls,
182          struct GNUNET_SERVER_Client *argclient,
183          const struct GNUNET_MessageHeader *message)
184 {
185   struct GNUNET_SERVER_Client *client;
186   struct CopyContext *cc;
187   struct GNUNET_MessageHeader *cpy;
188
189   GNUNET_assert (argclient == NULL);
190   GNUNET_assert (sizeof (struct GNUNET_MessageHeader) ==
191                  ntohs (message->size));
192   GNUNET_assert (MY_TYPE == ntohs (message->type));
193   client = GNUNET_SERVER_connect_callback (server,
194                                            cls,
195                                            &my_receive,
196                                            &my_cancel,
197                                            &my_transmit_ready_cb,
198                                            &my_transmit_ready_cancel_cb,
199                                            &my_check, &my_destroy);
200   cc = GNUNET_malloc (sizeof (struct CopyContext));
201   cc->client = client;
202   cpy = GNUNET_malloc (ntohs (message->size));
203   memcpy (cpy, message, ntohs (message->size));
204   cc->cpy = cpy;
205   GNUNET_assert (NULL !=
206                  GNUNET_SERVER_notify_transmit_ready (client,
207                                                       ntohs (message->size),
208                                                       GNUNET_TIME_UNIT_SECONDS,
209                                                       &copy_msg, cc));
210   GNUNET_SERVER_client_drop (client);
211 }
212
213
214 static struct GNUNET_SERVER_MessageHandler handlers[] = {
215   {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
216   {&recv_fin_cb, NULL, MY_TYPE2, sizeof (struct GNUNET_MessageHeader)},
217   {NULL, NULL, 0, 0}
218 };
219
220
221 static void
222 my_destroy (void *cls)
223 {
224   int *ok = cls;
225   GNUNET_assert (5 == *ok);
226   *ok = 0;                      /* report success */
227   /* this will cause us to terminate */
228   GNUNET_SERVER_destroy (server);
229 }
230
231
232 static void
233 task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
234 {
235   struct sockaddr_in sa;
236   struct GNUNET_MessageHeader msg;
237
238   sched = tc->sched;
239   memset (&sa, 0, sizeof (sa));
240 #if HAVE_SOCKADDR_IN_SIN_LEN
241   sa.sin_len = sizeof (sa);
242 #endif
243   sa.sin_family = AF_INET;
244   sa.sin_port = htons (PORT);
245   server = GNUNET_SERVER_create (tc->sched,
246                                  NULL,
247                                  NULL,
248                                  (const struct sockaddr *) &sa,
249                                  sizeof (sa),
250                                  1024,
251                                  GNUNET_TIME_relative_multiply
252                                  (GNUNET_TIME_UNIT_MILLISECONDS, 250),
253                                  GNUNET_NO);
254   GNUNET_assert (server != NULL);
255   handlers[0].callback_cls = cls;
256   handlers[1].callback_cls = cls;
257   GNUNET_SERVER_add_handlers (server, handlers);
258   msg.type = htons (MY_TYPE);
259   msg.size = htons (sizeof (struct GNUNET_MessageHeader));
260   GNUNET_SERVER_inject (server, NULL, &msg);
261   memset (&msg, 0, sizeof (struct GNUNET_MessageHeader));
262 }
263
264
265 /**
266  * Main method, starts scheduler with task1,
267  * checks that "ok" is correct at the end.
268  */
269 static int
270 check ()
271 {
272   int ok;
273
274   ok = 1;
275   GNUNET_SCHEDULER_run (&task, &ok);
276   return ok;
277 }
278
279
280 int
281 main (int argc, char *argv[])
282 {
283   int ret = 0;
284
285   GNUNET_log_setup ("test_server", "WARNING", NULL);
286   ret += check ();
287
288   return ret;
289 }
290
291 /* end of test_server.c */