Added SILC Thread Queue API
[silc.git] / lib / silcutil / tests / test_silcnet.c
1 /* SILC Net API tests */
2
3 #include "silc.h"
4
5 SilcSchedule schedule;
6
7 typedef struct {
8   SilcFSM fsm;
9   SilcFSMEventStruct sema;
10   SilcFSMThreadStruct thread;
11   SilcNetListener server;
12   SilcStream client_stream;
13   SilcResult client_status;
14   SilcStream server_stream;
15   SilcResult server_status;
16   SilcBool success;
17 } *Foo;
18
19 SILC_FSM_STATE(test_st_start);
20 SILC_FSM_STATE(test_st_second);
21 SILC_FSM_STATE(test_st_finish);
22
23 SILC_FSM_STATE(test_st_connect);
24 SILC_FSM_STATE(test_st_connected);
25
26 static void test_accept_connection(SilcResult status, SilcStream stream,
27                                    void *context)
28 {
29   Foo f = context;
30   SILC_LOG_DEBUG(("Accepted new connection"));
31   f->client_status = status;
32   f->client_stream = stream;
33   SILC_FSM_EVENT_SIGNAL(&f->sema);
34 }
35
36 static void test_connected(SilcResult status, SilcStream stream,
37                            void *context)
38 {
39   Foo f = context;
40   SILC_LOG_DEBUG(("Connected to server"));
41   f->server_status = status;
42   f->server_stream = stream;
43   SILC_FSM_CALL_CONTINUE(&f->thread);
44 }
45
46 SILC_FSM_STATE(test_st_connect)
47 {
48   Foo f = fsm_context;
49
50   SILC_LOG_DEBUG(("test_st_connect"));
51   SILC_LOG_DEBUG(("Connecting to server"));
52
53   silc_fsm_next(fsm, test_st_connected);
54   SILC_FSM_CALL(silc_net_tcp_connect(NULL, "localhost", 5000,
55                                      silc_fsm_get_schedule(fsm),
56                                      test_connected, f));
57 }
58
59 SILC_FSM_STATE(test_st_connected)
60 {
61   Foo f = fsm_context;
62   const char *host, *ip;
63   SilcUInt16 port;
64
65   SILC_LOG_DEBUG(("test_st_connected"));
66
67   if (f->server_status != SILC_OK) {
68     SILC_LOG_DEBUG(("Creating connection failed"));
69     return SILC_FSM_FINISH;
70   }
71
72   silc_socket_stream_get_info(f->server_stream, NULL, &host, &ip, &port);
73   SILC_LOG_DEBUG(("Connected to server %s, %s:%d", host, ip, port));
74
75   return SILC_FSM_FINISH;
76 }
77
78 SILC_FSM_STATE(test_st_start)
79 {
80   Foo f = fsm_context;
81   int ports[3];
82   SilcUInt16 *ret_ports;
83   SilcUInt32 port_count;
84
85   SILC_LOG_DEBUG(("test_st_start"));
86
87   SILC_LOG_DEBUG(("Creating network listener to ports 2000, 3000 and 4000"));
88   ports[0] = 2000;
89   ports[1] = 3000;
90   ports[2] = 4000;
91   f->server = silc_net_tcp_create_listener2(NULL, ports, 3, FALSE, TRUE, TRUE,
92                                      silc_fsm_get_schedule(fsm),
93                                      test_accept_connection, f);
94   if (!f->server) {
95     /** Creating network listener failed */
96     SILC_LOG_DEBUG(("Listener creation failed"));
97     silc_fsm_next(fsm, test_st_finish);
98     return SILC_FSM_CONTINUE;
99   }
100
101   ret_ports = silc_net_listener_get_port(f->server, &port_count);
102   if (!ret_ports) {
103     SILC_LOG_DEBUG(("Listener does not work"));
104     silc_fsm_next(fsm, test_st_finish);
105     return SILC_FSM_CONTINUE;
106   }
107   SILC_LOG_DEBUG(("Bound to port %d", ret_ports[0]));
108   SILC_LOG_DEBUG(("Bound to port %d", ret_ports[1]));
109   SILC_LOG_DEBUG(("Bound to port %d", ret_ports[2]));
110   silc_free(ret_ports);
111
112   /* Close this listener and create new one */
113   silc_net_close_listener(f->server);
114
115   SILC_LOG_DEBUG(("Creating network listener"));
116   f->server = silc_net_tcp_create_listener(NULL, 0, 5000, TRUE, TRUE,
117                                      silc_fsm_get_schedule(fsm),
118                                      test_accept_connection, f);
119   if (!f->server) {
120     /** Creating network listener failed */
121     SILC_LOG_DEBUG(("Listener creation failed"));
122     silc_fsm_next(fsm, test_st_finish);
123     return SILC_FSM_CONTINUE;
124   }
125
126   /* Create thread to connect to the listener */
127   silc_fsm_thread_init(&f->thread, fsm, f, NULL, NULL, FALSE);
128   silc_fsm_start(&f->thread, test_st_connect);
129
130   /** Start waiting connection */
131   SILC_LOG_DEBUG(("Start waiting for incoming connections"));
132   silc_fsm_event_init(&f->sema, fsm);
133   silc_fsm_next(fsm, test_st_second);
134   return SILC_FSM_CONTINUE;
135 }
136
137 SILC_FSM_STATE(test_st_second)
138 {
139   Foo f = fsm_context;
140   const char *ip, *host;
141   SilcUInt16 port;
142
143   SILC_LOG_DEBUG(("test_st_second"));
144
145   SILC_FSM_EVENT_WAIT(&f->sema);
146
147   if (f->client_status != SILC_OK) {
148     /** Accepting new connection failed */
149     SILC_LOG_DEBUG(("Accepting failed %d", f->client_status));
150     silc_fsm_next(fsm, test_st_finish);
151     return SILC_FSM_CONTINUE;
152   }
153
154   silc_socket_stream_get_info(f->client_stream, NULL, &host, &ip, &port);
155   SILC_LOG_DEBUG(("Accepted new connection %s, %s:%d", host, ip, port));
156
157   /** Wait thread to terminate */
158   f->success = TRUE;
159   silc_fsm_next(fsm, test_st_finish);
160   SILC_FSM_THREAD_WAIT(&f->thread);
161 }
162
163 SILC_FSM_STATE(test_st_finish)
164 {
165   Foo f = fsm_context;
166
167   SILC_LOG_DEBUG(("test_st_finish"));
168
169   if (f->server_stream) {
170     silc_stream_close(f->server_stream);
171     silc_stream_destroy(f->server_stream);
172   }
173   if (f->client_stream) {
174     silc_stream_close(f->client_stream);
175     silc_stream_destroy(f->client_stream);
176   }
177
178   SILC_LOG_DEBUG(("Closing network listener"));
179   silc_net_close_listener(f->server);
180
181   SILC_LOG_DEBUG(("Finish machine"));
182   return SILC_FSM_FINISH;
183 }
184
185 static void destructor(SilcFSM fsm, void *fsm_context,
186                        void *destructor_context)
187 {
188   SILC_LOG_DEBUG(("FSM destructor, stopping scheduler"));
189   silc_fsm_free(fsm);
190   silc_schedule_stop(schedule);
191 }
192
193 int main(int argc, char **argv)
194 {
195   SilcBool success = FALSE;
196   SilcFSM fsm;
197   Foo f;
198
199   if (argc > 1 && !strcmp(argv[1], "-d")) {
200     silc_log_debug(TRUE);
201     silc_log_debug_hexdump(TRUE);
202     silc_log_set_debug_string("*net*,*stream*,*errno*");
203   }
204
205   SILC_LOG_DEBUG(("Allocating scheduler"));
206   schedule = silc_schedule_init(0, NULL, NULL);
207
208   f = silc_calloc(1, sizeof(*f));
209   if (!f)
210     goto err;
211
212   SILC_LOG_DEBUG(("Allocating FSM context"));
213   fsm = silc_fsm_alloc(f, destructor, NULL, schedule);
214   if (!fsm)
215     goto err;
216   silc_fsm_start(fsm, test_st_start);
217   f->fsm = fsm;
218
219   SILC_LOG_DEBUG(("Running scheduler"));
220   silc_schedule(schedule);
221
222   if (!f->success)
223     goto err;
224
225   silc_schedule_uninit(schedule);
226   silc_free(f);
227
228   success = TRUE;
229
230  err:
231   SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
232   fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
233
234   return success;
235 }