New "reconnect" library for managing network connection attempts.
[sliver-openvswitch.git] / tests / test-reconnect.c
1 /*
2  * Copyright (c) 2009 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     int old_time;
44     char line[128];
45
46     now = 1000;
47     reconnect = reconnect_create(now);
48     reconnect_set_name(reconnect, "remote");
49     reconnect_get_stats(reconnect, now, &prev);
50     printf("### t=%d ###\n", now);
51     old_time = now;
52     while (fgets(line, sizeof line, stdin)) {
53         struct reconnect_stats cur;
54         struct svec args;
55
56         fputs(line, stdout);
57         if (line[0] == '#') {
58             continue;
59         }
60
61         svec_init(&args);
62         svec_parse_words(&args, line);
63         svec_terminate(&args);
64         if (!svec_is_empty(&args)) {
65             run_command(args.n, args.names, commands);
66         }
67         svec_destroy(&args);
68
69         if (old_time != now) {
70             printf("\n### t=%d ###\n", now);
71             old_time = now;
72         }
73
74         reconnect_get_stats(reconnect, now, &cur);
75         diff_stats(&prev, &cur);
76         prev = cur;
77     }
78
79     return 0;
80 }
81
82 static void
83 do_enable(int argc UNUSED, char *argv[] UNUSED)
84 {
85     reconnect_enable(reconnect, now);
86 }
87
88 static void
89 do_disable(int argc UNUSED, char *argv[] UNUSED)
90 {
91     reconnect_disable(reconnect, now);
92 }
93
94 static void
95 do_force_reconnect(int argc UNUSED, char *argv[] UNUSED)
96 {
97     reconnect_force_reconnect(reconnect, now);
98 }
99
100 static int
101 error_from_string(const char *s)
102 {
103     if (!s) {
104         return 0;
105     } else if (!strcmp(s, "ECONNREFUSED")) {
106         return ECONNREFUSED;
107     } else if (!strcmp(s, "EOF")) {
108         return EOF;
109     } else {
110         ovs_fatal(0, "unknown error '%s'", s);
111     }
112 }
113
114 static void
115 do_disconnected(int argc UNUSED, char *argv[])
116 {
117     reconnect_disconnected(reconnect, now, error_from_string(argv[1]));
118 }
119
120 static void
121 do_connecting(int argc UNUSED, char *argv[] UNUSED)
122 {
123     reconnect_connecting(reconnect, now);
124 }
125
126 static void
127 do_connect_failed(int argc UNUSED, char *argv[])
128 {
129     reconnect_connect_failed(reconnect, now, error_from_string(argv[1]));
130 }
131
132 static void
133 do_connected(int argc UNUSED, char *argv[] UNUSED)
134 {
135     reconnect_connected(reconnect, now);
136 }
137
138 static void
139 do_received(int argc UNUSED, char *argv[] UNUSED)
140 {
141     reconnect_received(reconnect, now);
142 }
143
144 static void
145 do_run(int argc, char *argv[])
146 {
147     enum reconnect_action action;
148
149     if (argc > 1) {
150         now += atoi(argv[1]);
151     }
152
153     action = reconnect_run(reconnect, now);
154     switch (action) {
155     default:
156         if (action != 0) {
157             NOT_REACHED();
158         }
159         break;
160
161     case RECONNECT_CONNECT:
162         printf("  should connect\n");
163         break;
164
165     case RECONNECT_DISCONNECT:
166         printf("  should disconnect\n");
167         break;
168
169     case RECONNECT_PROBE:
170         printf("  should send probe\n");
171         break;
172     }
173 }
174
175 static void
176 do_advance(int argc UNUSED, char *argv[])
177 {
178     now += atoi(argv[1]);
179 }
180
181 static void
182 do_timeout(int argc UNUSED, char *argv[] UNUSED)
183 {
184     int timeout = reconnect_timeout(reconnect, now);
185     if (timeout >= 0) {
186         printf("  advance %d ms\n", timeout);
187         now += timeout;
188     } else {
189         printf("  no timeout\n");
190     }
191 }
192
193 static void
194 diff_stats(const struct reconnect_stats *old,
195            const struct reconnect_stats *new)
196 {
197     if (old->state != new->state
198         || old->state_elapsed != new->state_elapsed
199         || old->backoff != new->backoff) {
200         printf("  in %s for %u ms (%d ms backoff)\n",
201                new->state, new->state_elapsed, new->backoff);
202     }
203     if (old->creation_time != new->creation_time
204         || old->last_received != new->last_received
205         || old->last_connected != new->last_connected) {
206         printf("  created %lld, last received %lld, last connected %lld\n",
207                new->creation_time, new->last_received, new->last_connected);
208     }
209     if (old->n_successful_connections != new->n_successful_connections
210         || old->n_attempted_connections != new->n_attempted_connections
211         || old->seqno != new->seqno) {
212         printf("  %u successful connections out of %u attempts, seqno %u\n",
213                new->n_successful_connections, new->n_attempted_connections,
214                new->seqno);
215     }
216     if (old->is_connected != new->is_connected
217         || old->current_connection_duration != new->current_connection_duration
218         || old->total_connected_duration != new->total_connected_duration) {
219         printf("  %sconnected (%u ms), total %u ms connected\n",
220                new->is_connected ? "" : "not ",
221                new->current_connection_duration,
222                new->total_connected_duration);
223     }
224 }
225
226 static const struct command commands[] = {
227     { "enable", 0, 0, do_enable },
228     { "disable", 0, 0, do_disable },
229     { "force-reconnect", 0, 0, do_force_reconnect },
230     { "disconnected", 0, 1, do_disconnected },
231     { "connecting", 0, 0, do_connecting },
232     { "connect-failed", 0, 1, do_connect_failed },
233     { "connected", 0, 0, do_connected },
234     { "received", 0, 0, do_received },
235     { "run", 0, 1, do_run },
236     { "advance", 1, 1, do_advance },
237     { "timeout", 0, 0, do_timeout },
238     { NULL, 0, 0, NULL },
239 };
240