Merge "citrix" branch into "master".
[sliver-openvswitch.git] / tests / test-reconnect.c
1 /*
2  * Copyright (c) 2009, 2010 Nicira Networks.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18
19 #include "reconnect.h"
20
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "command-line.h"
27 #include "compiler.h"
28 #include "svec.h"
29 #include "util.h"
30
31 static struct reconnect *reconnect;
32 static int now;
33
34 static const struct command commands[];
35
36 static void diff_stats(const struct reconnect_stats *old,
37                        const struct reconnect_stats *new);
38
39 int
40 main(void)
41 {
42     struct reconnect_stats prev;
43     unsigned int old_max_tries;
44     int old_time;
45     char line[128];
46
47     now = 1000;
48     reconnect = reconnect_create(now);
49     reconnect_set_name(reconnect, "remote");
50     reconnect_get_stats(reconnect, now, &prev);
51     printf("### t=%d ###\n", now);
52     old_time = now;
53     old_max_tries = reconnect_get_max_tries(reconnect);
54     while (fgets(line, sizeof line, stdin)) {
55         struct reconnect_stats cur;
56         struct svec args;
57
58         fputs(line, stdout);
59         if (line[0] == '#') {
60             continue;
61         }
62
63         svec_init(&args);
64         svec_parse_words(&args, line);
65         svec_terminate(&args);
66         if (!svec_is_empty(&args)) {
67             run_command(args.n, args.names, commands);
68         }
69         svec_destroy(&args);
70
71         if (old_time != now) {
72             printf("\n### t=%d ###\n", now);
73             old_time = now;
74         }
75
76         reconnect_get_stats(reconnect, now, &cur);
77         diff_stats(&prev, &cur);
78         prev = cur;
79         if (reconnect_get_max_tries(reconnect) != old_max_tries) {
80             old_max_tries = reconnect_get_max_tries(reconnect);
81             printf("  %u tries left\n", old_max_tries);
82         }
83     }
84
85     return 0;
86 }
87
88 static void
89 do_enable(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
90 {
91     reconnect_enable(reconnect, now);
92 }
93
94 static void
95 do_disable(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
96 {
97     reconnect_disable(reconnect, now);
98 }
99
100 static void
101 do_force_reconnect(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
102 {
103     reconnect_force_reconnect(reconnect, now);
104 }
105
106 static int
107 error_from_string(const char *s)
108 {
109     if (!s) {
110         return 0;
111     } else if (!strcmp(s, "ECONNREFUSED")) {
112         return ECONNREFUSED;
113     } else if (!strcmp(s, "EOF")) {
114         return EOF;
115     } else {
116         ovs_fatal(0, "unknown error '%s'", s);
117     }
118 }
119
120 static void
121 do_disconnected(int argc OVS_UNUSED, char *argv[])
122 {
123     reconnect_disconnected(reconnect, now, error_from_string(argv[1]));
124 }
125
126 static void
127 do_connecting(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
128 {
129     reconnect_connecting(reconnect, now);
130 }
131
132 static void
133 do_connect_failed(int argc OVS_UNUSED, char *argv[])
134 {
135     reconnect_connect_failed(reconnect, now, error_from_string(argv[1]));
136 }
137
138 static void
139 do_connected(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
140 {
141     reconnect_connected(reconnect, now);
142 }
143
144 static void
145 do_received(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
146 {
147     reconnect_received(reconnect, now);
148 }
149
150 static void
151 do_run(int argc, char *argv[])
152 {
153     enum reconnect_action action;
154
155     if (argc > 1) {
156         now += atoi(argv[1]);
157     }
158
159     action = reconnect_run(reconnect, now);
160     switch (action) {
161     default:
162         if (action != 0) {
163             NOT_REACHED();
164         }
165         break;
166
167     case RECONNECT_CONNECT:
168         printf("  should connect\n");
169         break;
170
171     case RECONNECT_DISCONNECT:
172         printf("  should disconnect\n");
173         break;
174
175     case RECONNECT_PROBE:
176         printf("  should send probe\n");
177         break;
178     }
179 }
180
181 static void
182 do_advance(int argc OVS_UNUSED, char *argv[])
183 {
184     now += atoi(argv[1]);
185 }
186
187 static void
188 do_timeout(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
189 {
190     int timeout = reconnect_timeout(reconnect, now);
191     if (timeout >= 0) {
192         printf("  advance %d ms\n", timeout);
193         now += timeout;
194     } else {
195         printf("  no timeout\n");
196     }
197 }
198
199 static void
200 do_set_max_tries(int argc OVS_UNUSED, char *argv[])
201 {
202     reconnect_set_max_tries(reconnect, atoi(argv[1]));
203 }
204
205 static void
206 diff_stats(const struct reconnect_stats *old,
207            const struct reconnect_stats *new)
208 {
209     if (old->state != new->state
210         || old->state_elapsed != new->state_elapsed
211         || old->backoff != new->backoff) {
212         printf("  in %s for %u ms (%d ms backoff)\n",
213                new->state, new->state_elapsed, new->backoff);
214     }
215     if (old->creation_time != new->creation_time
216         || old->last_received != new->last_received
217         || old->last_connected != new->last_connected) {
218         printf("  created %lld, last received %lld, last connected %lld\n",
219                new->creation_time, new->last_received, new->last_connected);
220     }
221     if (old->n_successful_connections != new->n_successful_connections
222         || old->n_attempted_connections != new->n_attempted_connections
223         || old->seqno != new->seqno) {
224         printf("  %u successful connections out of %u attempts, seqno %u\n",
225                new->n_successful_connections, new->n_attempted_connections,
226                new->seqno);
227     }
228     if (old->is_connected != new->is_connected
229         || old->current_connection_duration != new->current_connection_duration
230         || old->total_connected_duration != new->total_connected_duration) {
231         printf("  %sconnected (%u ms), total %u ms connected\n",
232                new->is_connected ? "" : "not ",
233                new->current_connection_duration,
234                new->total_connected_duration);
235     }
236 }
237
238 static const struct command commands[] = {
239     { "enable", 0, 0, do_enable },
240     { "disable", 0, 0, do_disable },
241     { "force-reconnect", 0, 0, do_force_reconnect },
242     { "disconnected", 0, 1, do_disconnected },
243     { "connecting", 0, 0, do_connecting },
244     { "connect-failed", 0, 1, do_connect_failed },
245     { "connected", 0, 0, do_connected },
246     { "received", 0, 0, do_received },
247     { "run", 0, 1, do_run },
248     { "advance", 1, 1, do_advance },
249     { "timeout", 0, 0, do_timeout },
250     { "set-max-tries", 1, 1, do_set_max_tries },
251     { NULL, 0, 0, NULL },
252 };
253