1 /* Copyright (C) 2007 Board of Trustees, Leland Stanford Jr. University.
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
31 #include "command-line.h"
35 #include "vconn-ssl.h"
37 #include "vlog-socket.h"
39 #include "poll-loop.h"
42 #define THIS_MODULE VLM_secchan
44 static void parse_options(int argc, char *argv[]);
45 static void usage(void) NO_RETURN;
47 static bool reliable = true;
53 time_t backoff_deadline;
57 static void reconnect(struct half *);
60 main(int argc, char *argv[])
62 struct half halves[2];
66 set_program_name(argv[0]);
67 register_fault_handlers();
69 parse_options(argc, argv);
71 if (argc - optind != 2) {
72 fatal(0, "exactly two peer arguments required; use --help for usage");
75 retval = vlog_server_listen(NULL, NULL);
77 fatal(retval, "Could not listen for vlog connections");
80 for (i = 0; i < 2; i++) {
81 halves[i].name = argv[optind + i];
82 halves[i].vconn = NULL;
83 halves[i].rxbuf = NULL;
84 halves[i].backoff_deadline = 0;
85 halves[i].backoff = 1;
86 reconnect(&halves[i]);
89 /* Do some work. Limit the number of iterations so that callbacks
90 * registered with the poll loop don't starve. */
92 for (iteration = 0; iteration < 50; iteration++) {
93 bool progress = false;
94 for (i = 0; i < 2; i++) {
95 struct half *this = &halves[i];
96 struct half *peer = &halves[!i];
99 retval = vconn_recv(this->vconn, &this->rxbuf);
100 if (retval && retval != EAGAIN) {
102 VLOG_DBG("%s: connection closed by remote host",
105 VLOG_DBG("%s: recv: closing connection: %s",
106 this->name, strerror(retval));
114 retval = vconn_send(peer->vconn, this->rxbuf);
118 } else if (retval != EAGAIN) {
119 VLOG_DBG("%s: send: closing connection: %s",
120 peer->name, strerror(retval));
131 /* Wait for something to happen. */
132 for (i = 0; i < 2; i++) {
133 struct half *this = &halves[i];
134 struct half *peer = &halves[!i];
136 vconn_recv_wait(this->vconn);
138 vconn_send_wait(peer->vconn);
148 reconnect(struct half *this)
150 if (this->vconn != NULL) {
152 fatal(0, "%s: connection dropped", this->name);
155 VLOG_WARN("%s: connection dropped, reconnecting", this->name);
156 vconn_close(this->vconn);
158 buffer_delete(this->rxbuf);
163 time_t now = time(0);
166 if (now >= this->backoff_deadline) {
170 if (this->backoff > 60) {
173 VLOG_WARN("%s: waiting %d seconds before reconnect\n",
174 this->name, (int) (this->backoff_deadline - now));
175 poll_timer_wait((this->backoff_deadline - now) * 1000);
179 retval = vconn_open_block(this->name, &this->vconn);
181 VLOG_WARN("%s: connected", this->name);
182 if (vconn_is_passive(this->vconn)) {
183 fatal(0, "%s: passive vconn not supported in control path",
186 this->backoff_deadline = now + this->backoff;
191 fatal(0, "%s: connection failed", this->name);
193 VLOG_WARN("%s: connection failed (%s)", this->name, strerror(retval));
194 this->backoff_deadline = time(0) + this->backoff;
199 parse_options(int argc, char *argv[])
201 static struct option long_options[] = {
202 {"unreliable", no_argument, 0, 'u'},
203 {"verbose", optional_argument, 0, 'v'},
204 {"help", no_argument, 0, 'h'},
205 {"version", no_argument, 0, 'V'},
207 {"private-key", required_argument, 0, 'p'},
208 {"certificate", required_argument, 0, 'c'},
209 {"ca-cert", required_argument, 0, 'C'},
213 char *short_options = long_options_to_short_options(long_options);
219 c = getopt_long(argc, argv, short_options, long_options, &indexptr);
233 printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]);
237 vlog_set_verbosity(optarg);
242 vconn_ssl_set_private_key_file(optarg);
246 vconn_ssl_set_certificate_file(optarg);
250 vconn_ssl_set_ca_cert_file(optarg);
267 printf("%s: Secure Channel\n"
268 "usage: %s [OPTIONS] LOCAL REMOTE\n"
269 "\nRelays OpenFlow message between LOCAL and REMOTE datapaths.\n"
270 "LOCAL and REMOTE must each be one of the following:\n"
271 " tcp:HOST[:PORT] PORT (default: %d) on remote TCP HOST\n",
272 program_name, program_name, OFP_TCP_PORT);
274 printf(" nl:DP_IDX local datapath DP_IDX\n");
277 printf(" ssl:HOST[:PORT] SSL PORT (default: %d) on remote HOST\n"
278 "\nPKI configuration (required to use SSL):\n"
279 " -p, --private-key=FILE file with private key\n"
280 " -c, --certificate=FILE file with certificate for private key\n"
281 " -C, --ca-cert=FILE file with peer CA certificate\n",
284 printf("\nNetworking options:\n"
285 " -u, --unreliable do not reconnect after connections drop\n"
287 " -v, --verbose set maximum verbosity level\n"
288 " -h, --help display this help message\n"
289 " -V, --version display version information\n");