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"
41 #define THIS_MODULE VLM_secchan
43 static void parse_options(int argc, char *argv[]);
44 static void usage(void) NO_RETURN;
46 static bool reliable = true;
51 struct pollfd *pollfd;
53 time_t backoff_deadline;
57 static void reconnect(struct half *);
60 main(int argc, char *argv[])
62 struct half halves[2];
63 struct pollfd pollfds[2 + 1];
64 struct vlog_server *vlog_server;
68 set_program_name(argv[0]);
69 register_fault_handlers();
71 parse_options(argc, argv);
73 if (argc - optind != 2) {
74 fatal(0, "exactly two peer arguments required; use --help for usage");
77 retval = vlog_server_listen(NULL, &vlog_server);
79 fatal(retval, "Could not listen for vlog connections");
82 for (i = 0; i < 2; i++) {
83 halves[i].name = argv[optind + i];
84 halves[i].vconn = NULL;
85 halves[i].pollfd = &pollfds[i];
86 halves[i].rxbuf = NULL;
87 halves[i].backoff_deadline = 0;
88 halves[i].backoff = 1;
89 reconnect(&halves[i]);
94 /* Wait until there's something to do. */
96 for (i = 0; i < 2; i++) {
97 struct half *this = &halves[i];
98 struct half *peer = &halves[!i];
106 this->pollfd->fd = -1;
107 this->pollfd->events = 0;
108 n_ready += vconn_prepoll(this->vconn, want, this->pollfd);
111 pollfds[2].fd = vlog_server_get_fd(vlog_server);
112 pollfds[2].events = POLLIN;
115 retval = poll(pollfds, 2 + (vlog_server != NULL),
117 } while (retval < 0 && errno == EINTR);
118 if (retval < 0 || (retval == 0 && !n_ready)) {
119 fatal(retval < 0 ? errno : 0, "poll");
122 /* Let each connection deal with any pending operations. */
123 for (i = 0; i < 2; i++) {
124 struct half *this = &halves[i];
125 vconn_postpoll(this->vconn, &this->pollfd->revents);
126 if (this->pollfd->revents & POLLERR) {
127 this->pollfd->revents |= POLLIN | POLLOUT;
130 if (vlog_server && pollfds[2].revents) {
131 vlog_server_poll(vlog_server);
134 /* Do as much work as we can without waiting. */
135 for (i = 0; i < 2; i++) {
136 struct half *this = &halves[i];
137 struct half *peer = &halves[!i];
139 if (this->pollfd->revents & POLLIN && !this->rxbuf) {
140 retval = vconn_recv(this->vconn, &this->rxbuf);
141 if (retval && retval != EAGAIN) {
142 VLOG_DBG("%s: recv: closing connection: %s",
143 this->name, strerror(retval));
149 if (peer->pollfd->revents & POLLOUT && this->rxbuf) {
150 retval = vconn_send(peer->vconn, this->rxbuf);
153 } else if (retval != EAGAIN) {
154 VLOG_DBG("%s: send: closing connection: %s",
155 peer->name, strerror(retval));
167 reconnect(struct half *this)
169 if (this->vconn != NULL) {
171 fatal(0, "%s: connection dropped", this->name);
174 VLOG_WARN("%s: connection dropped, reconnecting", this->name);
175 vconn_close(this->vconn);
177 buffer_delete(this->rxbuf);
180 this->pollfd->revents = POLLIN | POLLOUT;
183 time_t now = time(0);
186 if (now >= this->backoff_deadline) {
190 if (this->backoff > 60) {
193 VLOG_WARN("%s: waiting %d seconds before reconnect\n",
194 this->name, (int) (this->backoff_deadline - now));
195 sleep(this->backoff_deadline - now);
198 retval = vconn_open(this->name, &this->vconn);
200 VLOG_WARN("%s: connected", this->name);
201 if (vconn_is_passive(this->vconn)) {
202 fatal(0, "%s: passive vconn not supported in control path",
205 this->backoff_deadline = now + this->backoff;
210 fatal(0, "%s: connection failed", this->name);
212 VLOG_WARN("%s: connection failed (%s)", this->name, strerror(errno));
213 this->backoff_deadline = time(0) + this->backoff;
218 parse_options(int argc, char *argv[])
220 static struct option long_options[] = {
221 {"unreliable", no_argument, 0, 'u'},
222 {"verbose", optional_argument, 0, 'v'},
223 {"help", no_argument, 0, 'h'},
224 {"version", no_argument, 0, 'V'},
226 {"private-key", required_argument, 0, 'p'},
227 {"certificate", required_argument, 0, 'c'},
228 {"ca-cert", required_argument, 0, 'C'},
232 char *short_options = long_options_to_short_options(long_options);
238 c = getopt_long(argc, argv, short_options, long_options, &indexptr);
252 printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]);
256 vlog_set_verbosity(optarg);
261 vconn_ssl_set_private_key_file(optarg);
265 vconn_ssl_set_certificate_file(optarg);
269 vconn_ssl_set_ca_cert_file(optarg);
286 printf("%s: Secure Channel\n"
287 "usage: %s [OPTIONS] LOCAL REMOTE\n"
288 "\nRelays OpenFlow message between LOCAL and REMOTE datapaths.\n"
289 "LOCAL and REMOTE must each be one of the following:\n"
290 " tcp:HOST[:PORT] PORT (default: %d) on remote TCP HOST\n",
291 program_name, program_name, OFP_TCP_PORT);
293 printf(" nl:DP_IDX local datapath DP_IDX\n");
296 printf(" ssl:HOST[:PORT] SSL PORT (default: %d) on remote HOST\n"
297 "\nPKI configuration (required to use SSL):\n"
298 " -p, --private-key=FILE file with private key\n"
299 " -c, --certificate=FILE file with certificate for private key\n"
300 " -C, --ca-cert=FILE file with peer CA certificate\n",
303 printf("\nNetworking options:\n"
304 " -u, --unreliable do not reconnect after connections drop\n"
306 " -v, --verbose set maximum verbosity level\n"
307 " -h, --help display this help message\n"
308 " -V, --version display version information\n");