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
30 #include "command-line.h"
35 #include "vlog-socket.h"
39 #define THIS_MODULE VLM_secchan
41 static void parse_options(int argc, char *argv[]);
42 static void usage(void) NO_RETURN;
44 static bool reliable = true;
49 struct pollfd *pollfd;
53 static void reconnect(struct half *);
56 main(int argc, char *argv[])
58 struct half halves[2];
59 struct pollfd pollfds[2 + 1];
60 struct vlog_server *vlog_server;
64 set_program_name(argv[0]);
65 register_fault_handlers();
67 parse_options(argc, argv);
69 if (argc - optind != 2) {
70 fatal(0, "exactly two peer arguments required; use --help for usage");
73 retval = vlog_server_listen(NULL, &vlog_server);
75 fatal(retval, "Could not listen for vlog connections");
78 for (i = 0; i < 2; i++) {
79 halves[i].name = argv[optind + i];
80 halves[i].vconn = NULL;
81 halves[i].pollfd = &pollfds[i];
82 halves[i].rxbuf = NULL;
83 reconnect(&halves[i]);
86 /* Wait until there's something to do. */
87 for (i = 0; i < 2; i++) {
88 struct half *this = &halves[i];
89 struct half *peer = &halves[!i];
97 this->pollfd->fd = -1;
98 this->pollfd->events = 0;
99 vconn_prepoll(this->vconn, want, this->pollfd);
102 pollfds[2].fd = vlog_server_get_fd(vlog_server);
103 pollfds[2].events = POLLIN;
106 retval = poll(pollfds, 2 + (vlog_server != NULL), -1);
107 } while (retval < 0 && errno == EINTR);
109 fatal(retval < 0 ? errno : 0, "poll");
112 /* Let each connection deal with any pending operations. */
113 for (i = 0; i < 2; i++) {
114 struct half *this = &halves[i];
115 vconn_postpoll(this->vconn, &this->pollfd->revents);
116 if (this->pollfd->revents & POLLERR) {
117 this->pollfd->revents |= POLLIN | POLLOUT;
120 if (vlog_server && pollfds[2].revents) {
121 vlog_server_poll(vlog_server);
124 /* Do as much work as we can without waiting. */
125 for (i = 0; i < 2; i++) {
126 struct half *this = &halves[i];
127 struct half *peer = &halves[!i];
129 if (this->pollfd->revents & POLLIN && !this->rxbuf) {
130 retval = vconn_recv(this->vconn, &this->rxbuf);
131 if (retval && retval != EAGAIN) {
132 VLOG_DBG("%s: recv: closing connection: %s",
133 this->name, strerror(retval));
139 if (peer->pollfd->revents & POLLOUT && this->rxbuf) {
140 retval = vconn_send(peer->vconn, this->rxbuf);
143 } else if (retval != EAGAIN) {
144 VLOG_DBG("%s: send: closing connection: %s",
145 peer->name, strerror(retval));
157 reconnect(struct half *this)
161 if (this->vconn != NULL) {
163 fatal(0, "%s: connection dropped", this->name);
166 VLOG_WARN("%s: connection dropped, reconnecting", this->name);
167 vconn_close(this->vconn);
169 buffer_delete(this->rxbuf);
172 this->pollfd->revents = POLLIN | POLLOUT;
174 for (backoff = 1; ; backoff = MIN(backoff * 2, 60)) {
175 int retval = vconn_open(this->name, &this->vconn);
177 VLOG_WARN("%s: connected", this->name);
178 if (vconn_is_passive(this->vconn)) {
179 fatal(0, "%s: passive vconn not supported in control path",
186 fatal(0, "%s: connection failed", this->name);
188 VLOG_WARN("%s: connection failed (%s), reconnecting",
189 this->name, strerror(errno));
195 parse_options(int argc, char *argv[])
197 static struct option long_options[] = {
198 {"unreliable", no_argument, 0, 'u'},
199 {"verbose", optional_argument, 0, 'v'},
200 {"help", no_argument, 0, 'h'},
201 {"version", no_argument, 0, 'V'},
204 char *short_options = long_options_to_short_options(long_options);
210 c = getopt_long(argc, argv, short_options, long_options, &indexptr);
224 printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]);
228 vlog_set_verbosity(optarg);
244 printf("%s: Secure Channel\n"
245 "usage: %s [OPTIONS] nl:DP_ID tcp:HOST:[PORT]\n"
246 "\nConnects to local datapath DP_ID via Netlink and \n"
247 "controller on HOST via TCP to PORT (default: %d).\n"
248 "\nNetworking options:\n"
249 " -u, --unreliable do not reconnect after connections drop\n"
251 " -v, --verbose set maximum verbosity level\n"
252 " -h, --help display this help message\n"
253 " -V, --version display version information\n",
254 program_name, program_name, OFP_TCP_PORT);