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