Added SILC Buffer Stream API
[runtime.git] / lib / silcutil / tests / test_silcbufferstream.c
1 /* SILC Buffer Stream tests */
2
3 #include "silcruntime.h"
4
5 SilcSchedule schedule;
6
7 typedef struct {
8   SilcFSM fsm;
9   SilcFSMEventStruct sema;
10   SilcFSMEventStruct s_sema;
11   SilcFSMEventStruct c_sema;
12   SilcFSMThreadStruct thread;
13   SilcNetListener server;
14   SilcStream client_stream;
15   SilcStream cbuf;
16   int c_num_buf;
17   SilcResult client_status;
18   SilcStream server_stream;
19   SilcStream sbuf;
20   int s_num_buf;
21   SilcResult server_status;
22   SilcBool success;
23 } *Foo;
24
25 SILC_FSM_STATE(test_st_start);
26 SILC_FSM_STATE(test_st_second);
27 SILC_FSM_STATE(test_st_finish);
28
29 SILC_FSM_STATE(test_st_connect);
30 SILC_FSM_STATE(test_st_connected);
31
32 SILC_FSM_STATE(test_st_s_send_buffers);
33 SILC_FSM_STATE(test_st_s_receive_buffers);
34 SILC_FSM_STATE(test_st_c_send_buffers);
35 SILC_FSM_STATE(test_st_c_receive_buffers);
36
37 static void test_accept_connection(SilcResult status, SilcStream stream,
38                                    void *context)
39 {
40   Foo f = context;
41   SILC_LOG_DEBUG(("Accepted new connection"));
42   f->client_status = status;
43   f->client_stream = stream;
44   SILC_FSM_EVENT_SIGNAL(&f->sema);
45 }
46
47 static void test_connected(SilcResult status, SilcStream stream,
48                            void *context)
49 {
50   Foo f = context;
51   SILC_LOG_DEBUG(("Connected to server"));
52   f->server_status = status;
53   f->server_stream = stream;
54   SILC_FSM_CALL_CONTINUE(&f->thread);
55 }
56
57 static void receive_s_buffer(SilcResult status, SilcStream stream,
58                              SilcBuffer buffer, void *context)
59 {
60   Foo f = context;
61   SILC_LOG_DEBUG(("Received buffer"));
62   silc_buffer_free(buffer);
63   SILC_FSM_EVENT_SIGNAL(&f->s_sema);
64 }
65
66 static void receive_c_buffer(SilcResult status, SilcStream stream,
67                              SilcBuffer buffer, void *context)
68 {
69   Foo f = context;
70   SILC_LOG_DEBUG(("Received buffer"));
71   silc_buffer_free(buffer);
72   SILC_FSM_EVENT_SIGNAL(&f->c_sema);
73 }
74
75 SILC_FSM_STATE(test_st_connect)
76 {
77   Foo f = fsm_context;
78
79   SILC_LOG_DEBUG(("test_st_connect"));
80   SILC_LOG_DEBUG(("Connecting to server"));
81
82   silc_fsm_next(fsm, test_st_connected);
83   SILC_FSM_CALL(silc_net_tcp_connect(NULL, "localhost", 5000,
84                                      silc_fsm_get_schedule(fsm),
85                                      test_connected, f));
86 }
87
88 SILC_FSM_STATE(test_st_connected)
89 {
90   Foo f = fsm_context;
91   const char *host, *ip;
92   SilcUInt16 port;
93
94   SILC_LOG_DEBUG(("test_st_connected"));
95
96   if (f->server_status != SILC_OK) {
97     SILC_LOG_DEBUG(("Creating connection failed"));
98     return SILC_FSM_FINISH;
99   }
100
101   silc_socket_stream_get_info(f->server_stream, NULL, &host, &ip, &port);
102   SILC_LOG_DEBUG(("Connected to server %s, %s:%d", host, ip, port));
103
104   f->sbuf = silc_buffer_stream_create(f->server_stream,
105                                       receive_c_buffer, f);
106   if (!f->sbuf) {
107     silc_fsm_next(fsm, test_st_finish);
108     return SILC_FSM_CONTINUE;
109   }
110
111   silc_fsm_next(fsm, test_st_c_receive_buffers);
112   return SILC_FSM_CONTINUE;
113 }
114
115 SILC_FSM_STATE(test_st_start)
116 {
117   Foo f = fsm_context;
118   int ports[3];
119   SilcUInt16 *ret_ports;
120   SilcUInt32 port_count;
121
122   SILC_LOG_DEBUG(("test_st_start"));
123
124   SILC_LOG_DEBUG(("Creating network listener to ports 2000, 3000 and 4000"));
125   ports[0] = 2000;
126   ports[1] = 3000;
127   ports[2] = 4000;
128   f->server = silc_net_tcp_create_listener2(NULL, ports, 3, FALSE, TRUE, TRUE,
129                                      silc_fsm_get_schedule(fsm),
130                                      test_accept_connection, f);
131   if (!f->server) {
132     /** Creating network listener failed */
133     SILC_LOG_DEBUG(("Listener creation failed"));
134     silc_fsm_next(fsm, test_st_finish);
135     return SILC_FSM_CONTINUE;
136   }
137
138   ret_ports = silc_net_listener_get_port(f->server, &port_count);
139   if (!ret_ports) {
140     SILC_LOG_DEBUG(("Listener does not work"));
141     silc_fsm_next(fsm, test_st_finish);
142     return SILC_FSM_CONTINUE;
143   }
144   SILC_LOG_DEBUG(("Bound to port %d", ret_ports[0]));
145   SILC_LOG_DEBUG(("Bound to port %d", ret_ports[1]));
146   SILC_LOG_DEBUG(("Bound to port %d", ret_ports[2]));
147   silc_free(ret_ports);
148
149   /* Close this listener and create new one */
150   silc_net_close_listener(f->server);
151
152   SILC_LOG_DEBUG(("Creating network listener"));
153   f->server = silc_net_tcp_create_listener(NULL, 0, 5000, TRUE, TRUE,
154                                      silc_fsm_get_schedule(fsm),
155                                      test_accept_connection, f);
156   if (!f->server) {
157     /** Creating network listener failed */
158     SILC_LOG_DEBUG(("Listener creation failed"));
159     silc_fsm_next(fsm, test_st_finish);
160     return SILC_FSM_CONTINUE;
161   }
162
163   /* Create thread to connect to the listener */
164   silc_fsm_thread_init(&f->thread, fsm, f, NULL, NULL, FALSE);
165   silc_fsm_start(&f->thread, test_st_connect);
166
167   /** Start waiting connection */
168   SILC_LOG_DEBUG(("Start waiting for incoming connections"));
169   silc_fsm_event_init(&f->sema, fsm);
170   silc_fsm_next(fsm, test_st_second);
171   return SILC_FSM_CONTINUE;
172 }
173
174 SILC_FSM_STATE(test_st_second)
175 {
176   Foo f = fsm_context;
177   const char *ip, *host;
178   SilcUInt16 port;
179
180   SILC_LOG_DEBUG(("test_st_second"));
181
182   SILC_FSM_EVENT_WAIT(&f->sema);
183
184   if (f->client_status != SILC_OK) {
185     /** Accepting new connection failed */
186     SILC_LOG_DEBUG(("Accepting failed %d", f->client_status));
187     silc_fsm_next(fsm, test_st_finish);
188     return SILC_FSM_CONTINUE;
189   }
190
191   silc_socket_stream_get_info(f->client_stream, NULL, &host, &ip, &port);
192   SILC_LOG_DEBUG(("Accepted new connection %s, %s:%d", host, ip, port));
193
194   f->cbuf = silc_buffer_stream_create(f->client_stream,
195                                       receive_s_buffer, f);
196   if (!f->cbuf) {
197     silc_fsm_next(fsm, test_st_finish);
198     return SILC_FSM_CONTINUE;
199   }
200
201   silc_fsm_next(fsm, test_st_s_send_buffers);
202   return SILC_FSM_CONTINUE;
203 }
204
205 SILC_FSM_STATE(test_st_s_send_buffers)
206 {
207   Foo f = fsm_context;
208   SilcBuffer buffer;
209   int i;
210
211   SILC_LOG_DEBUG(("test_st_s_send_buffers"));
212
213   for (i = 0; i < 10; i++) {
214     buffer = silc_buffer_alloc_size(99 * (i + 1));
215     if (!buffer) {
216       silc_fsm_next(fsm, test_st_finish);
217       return SILC_FSM_CONTINUE;
218     }
219
220     SILC_LOG_HEXDUMP(("Send buffer %d to client", i + 1),
221                      silc_buffer_data(buffer), silc_buffer_len(buffer));
222
223     if (!silc_buffer_stream_send(f->cbuf, buffer)) {
224       silc_fsm_next(fsm, test_st_finish);
225       return SILC_FSM_CONTINUE;
226     }
227
228     silc_buffer_free(buffer);
229   }
230
231   silc_fsm_next(fsm, test_st_s_receive_buffers);
232   return SILC_FSM_CONTINUE;
233 }
234
235 SILC_FSM_STATE(test_st_s_receive_buffers)
236 {
237   Foo f = fsm_context;
238
239   SILC_LOG_DEBUG(("test_st_s_receive_buffers"));
240
241   SILC_FSM_EVENT_WAIT(&f->s_sema);
242
243   f->s_num_buf++;
244   SILC_LOG_DEBUG(("Received buffer %d", f->s_num_buf));
245   if (f->s_num_buf < 10)
246     return SILC_FSM_CONTINUE;
247
248   /** Wait thread to terminate */
249   f->success = TRUE;
250   silc_fsm_next(fsm, test_st_finish);
251   return SILC_FSM_CONTINUE;
252 }
253
254 SILC_FSM_STATE(test_st_c_receive_buffers)
255 {
256   Foo f = fsm_context;
257
258   SILC_LOG_DEBUG(("test_st_c_receive_buffers"));
259
260   SILC_FSM_EVENT_WAIT(&f->c_sema);
261
262   f->c_num_buf++;
263   SILC_LOG_DEBUG(("Received buffer %d", f->c_num_buf));
264   if (f->c_num_buf < 10)
265     return SILC_FSM_CONTINUE;
266
267   silc_fsm_next(fsm, test_st_c_send_buffers);
268   return SILC_FSM_CONTINUE;
269 }
270
271 SILC_FSM_STATE(test_st_c_send_buffers)
272 {
273   Foo f = fsm_context;
274   SilcBuffer buffer;
275   int i;
276
277   SILC_LOG_DEBUG(("test_st_c_send_buffers"));
278
279   for (i = 0; i < 10; i++) {
280     buffer = silc_buffer_alloc_size(13 * (i + 1));
281     if (!buffer)
282       continue;
283
284     SILC_LOG_HEXDUMP(("Send buffer %d to server", i + 1),
285                      silc_buffer_data(buffer), silc_buffer_len(buffer));
286
287     if (!silc_buffer_stream_send(f->sbuf, buffer)) {
288       silc_fsm_next(fsm, test_st_finish);
289       return SILC_FSM_CONTINUE;
290     }
291
292     silc_buffer_free(buffer);
293   }
294
295   return SILC_FSM_FINISH;
296 }
297
298 SILC_FSM_STATE(test_st_finish)
299 {
300   Foo f = fsm_context;
301
302   SILC_LOG_DEBUG(("test_st_finish"));
303
304   if (f->sbuf)
305     silc_stream_destroy(f->sbuf);
306   if (f->cbuf)
307     silc_stream_destroy(f->cbuf);
308   if (f->server_stream) {
309     silc_stream_close(f->server_stream);
310     silc_stream_destroy(f->server_stream);
311   }
312   if (f->client_stream) {
313     silc_stream_close(f->client_stream);
314     silc_stream_destroy(f->client_stream);
315   }
316
317   SILC_LOG_DEBUG(("Closing network listener"));
318   silc_net_close_listener(f->server);
319
320   SILC_LOG_DEBUG(("Finish machine"));
321   return SILC_FSM_FINISH;
322 }
323
324 static void destructor(SilcFSM fsm, void *fsm_context,
325                        void *destructor_context)
326 {
327   SILC_LOG_DEBUG(("FSM destructor, stopping scheduler"));
328   silc_fsm_free(fsm);
329   silc_schedule_stop(schedule);
330 }
331
332 int main(int argc, char **argv)
333 {
334   SilcBool success = FALSE;
335   SilcFSM fsm;
336   Foo f;
337
338   if (argc > 1 && !strcmp(argv[1], "-d")) {
339     silc_log_debug(TRUE);
340     silc_log_debug_hexdump(TRUE);
341     silc_log_set_debug_string("*net*,*stream*,*errno*");
342   }
343
344   SILC_LOG_DEBUG(("Allocating scheduler"));
345   schedule = silc_schedule_init(0, NULL, NULL, NULL);
346
347   f = silc_calloc(1, sizeof(*f));
348   if (!f)
349     goto err;
350
351   SILC_LOG_DEBUG(("Allocating FSM context"));
352   fsm = silc_fsm_alloc(f, destructor, NULL, schedule);
353   if (!fsm)
354     goto err;
355   silc_fsm_start(fsm, test_st_start);
356   f->fsm = fsm;
357
358   silc_fsm_event_init(&f->s_sema, fsm);
359   silc_fsm_event_init(&f->c_sema, fsm);
360
361   SILC_LOG_DEBUG(("Running scheduler"));
362   silc_schedule(schedule);
363
364   if (!f->success)
365     goto err;
366
367   silc_schedule_uninit(schedule);
368   silc_free(f);
369
370   success = TRUE;
371
372  err:
373   SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
374   fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
375
376   return !success;
377 }