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"
36 #include "vlog-socket.h"
40 #define THIS_MODULE VLM_secchan
42 static void parse_options(int argc, char *argv[]);
43 static void usage(void) NO_RETURN;
45 static bool reliable = true;
50 struct pollfd *pollfd;
52 time_t backoff_deadline;
56 static void reconnect(struct half *);
59 main(int argc, char *argv[])
61 struct half halves[2];
62 struct pollfd pollfds[2 + 1];
63 struct vlog_server *vlog_server;
67 set_program_name(argv[0]);
68 register_fault_handlers();
70 parse_options(argc, argv);
72 if (argc - optind != 2) {
73 fatal(0, "exactly two peer arguments required; use --help for usage");
76 retval = vlog_server_listen(NULL, &vlog_server);
78 fatal(retval, "Could not listen for vlog connections");
81 for (i = 0; i < 2; i++) {
82 halves[i].name = argv[optind + i];
83 halves[i].vconn = NULL;
84 halves[i].pollfd = &pollfds[i];
85 halves[i].rxbuf = NULL;
86 halves[i].backoff_deadline = 0;
87 halves[i].backoff = 1;
88 reconnect(&halves[i]);
93 /* Wait until there's something to do. */
95 for (i = 0; i < 2; i++) {
96 struct half *this = &halves[i];
97 struct half *peer = &halves[!i];
105 this->pollfd->fd = -1;
106 this->pollfd->events = 0;
107 n_ready += vconn_prepoll(this->vconn, want, this->pollfd);
110 pollfds[2].fd = vlog_server_get_fd(vlog_server);
111 pollfds[2].events = POLLIN;
114 retval = poll(pollfds, 2 + (vlog_server != NULL),
116 } while (retval < 0 && errno == EINTR);
117 if (retval < 0 || (retval == 0 && !n_ready)) {
118 fatal(retval < 0 ? errno : 0, "poll");
121 /* Let each connection deal with any pending operations. */
122 for (i = 0; i < 2; i++) {
123 struct half *this = &halves[i];
124 vconn_postpoll(this->vconn, &this->pollfd->revents);
125 if (this->pollfd->revents & POLLERR) {
126 this->pollfd->revents |= POLLIN | POLLOUT;
129 if (vlog_server && pollfds[2].revents) {
130 vlog_server_poll(vlog_server);
133 /* Do as much work as we can without waiting. */
134 for (i = 0; i < 2; i++) {
135 struct half *this = &halves[i];
136 struct half *peer = &halves[!i];
138 if (this->pollfd->revents & POLLIN && !this->rxbuf) {
139 retval = vconn_recv(this->vconn, &this->rxbuf);
140 if (retval && retval != EAGAIN) {
141 VLOG_DBG("%s: recv: closing connection: %s",
142 this->name, strerror(retval));
148 if (peer->pollfd->revents & POLLOUT && this->rxbuf) {
149 retval = vconn_send(peer->vconn, this->rxbuf);
152 } else if (retval != EAGAIN) {
153 VLOG_DBG("%s: send: closing connection: %s",
154 peer->name, strerror(retval));
166 reconnect(struct half *this)
168 if (this->vconn != NULL) {
170 fatal(0, "%s: connection dropped", this->name);
173 VLOG_WARN("%s: connection dropped, reconnecting", this->name);
174 vconn_close(this->vconn);
176 buffer_delete(this->rxbuf);
179 this->pollfd->revents = POLLIN | POLLOUT;
182 time_t now = time(0);
185 if (now >= this->backoff_deadline) {
189 if (this->backoff > 60) {
192 VLOG_WARN("%s: waiting %d seconds before reconnect\n",
193 this->name, (int) (this->backoff_deadline - now));
194 sleep(this->backoff_deadline - now);
197 retval = vconn_open(this->name, &this->vconn);
199 VLOG_WARN("%s: connected", this->name);
200 if (vconn_is_passive(this->vconn)) {
201 fatal(0, "%s: passive vconn not supported in control path",
204 this->backoff_deadline = now + this->backoff;
209 fatal(0, "%s: connection failed", this->name);
211 VLOG_WARN("%s: connection failed (%s)", this->name, strerror(errno));
212 this->backoff_deadline = time(0) + this->backoff;
217 parse_options(int argc, char *argv[])
219 static struct option long_options[] = {
220 {"unreliable", no_argument, 0, 'u'},
221 {"verbose", optional_argument, 0, 'v'},
222 {"help", no_argument, 0, 'h'},
223 {"version", no_argument, 0, 'V'},
225 {"private-key", required_argument, 0, 'p'},
226 {"certificate", required_argument, 0, 'c'},
227 {"ca-cert", required_argument, 0, 'C'},
231 char *short_options = long_options_to_short_options(long_options);
237 c = getopt_long(argc, argv, short_options, long_options, &indexptr);
251 printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]);
255 vlog_set_verbosity(optarg);
260 vconn_ssl_set_private_key_file(optarg);
264 vconn_ssl_set_certificate_file(optarg);
268 vconn_ssl_set_ca_cert_file(optarg);
285 printf("%s: Secure Channel\n"
286 "usage: %s [OPTIONS] LOCAL REMOTE\n"
287 "\nRelays OpenFlow message between LOCAL and REMOTE datapaths.\n"
288 "LOCAL and REMOTE must each be one of the following:\n"
289 " tcp:HOST[:PORT] PORT (default: %d) on remote TCP HOST\n",
290 program_name, program_name);
292 printf(" nl:DP_IDX local datapath DP_IDX\n");
295 printf(" ssl:HOST[:PORT] SSL PORT (default: %d) on remote HOST\n"
296 "\nPKI configuration (required to use SSL):\n"
297 " -p, --private-key=FILE file with private key\n"
298 " -c, --certificate=FILE file with certificate for private key\n"
299 " -C, --ca-cert=FILE file with peer CA certificate\n",
302 printf("\nNetworking options:\n"
303 " -u, --unreliable do not reconnect after connections drop\n"
305 " -v, --verbose set maximum verbosity level\n"
306 " -h, --help display this help message\n"
307 " -V, --version display version information\n",