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]);
91 /* Wait until there's something to do. */
92 for (i = 0; i < 2; i++) {
93 struct half *this = &halves[i];
94 struct half *peer = &halves[!i];
102 this->pollfd->fd = -1;
103 this->pollfd->events = 0;
104 vconn_prepoll(this->vconn, want, this->pollfd);
107 pollfds[2].fd = vlog_server_get_fd(vlog_server);
108 pollfds[2].events = POLLIN;
111 retval = poll(pollfds, 2 + (vlog_server != NULL), -1);
112 } while (retval < 0 && errno == EINTR);
114 fatal(retval < 0 ? errno : 0, "poll");
117 /* Let each connection deal with any pending operations. */
118 for (i = 0; i < 2; i++) {
119 struct half *this = &halves[i];
120 vconn_postpoll(this->vconn, &this->pollfd->revents);
121 if (this->pollfd->revents & POLLERR) {
122 this->pollfd->revents |= POLLIN | POLLOUT;
125 if (vlog_server && pollfds[2].revents) {
126 vlog_server_poll(vlog_server);
129 /* Do as much work as we can without waiting. */
130 for (i = 0; i < 2; i++) {
131 struct half *this = &halves[i];
132 struct half *peer = &halves[!i];
134 if (this->pollfd->revents & POLLIN && !this->rxbuf) {
135 retval = vconn_recv(this->vconn, &this->rxbuf);
136 if (retval && retval != EAGAIN) {
137 VLOG_DBG("%s: recv: closing connection: %s",
138 this->name, strerror(retval));
144 if (peer->pollfd->revents & POLLOUT && this->rxbuf) {
145 retval = vconn_send(peer->vconn, this->rxbuf);
148 } else if (retval != EAGAIN) {
149 VLOG_DBG("%s: send: closing connection: %s",
150 peer->name, strerror(retval));
162 reconnect(struct half *this)
164 if (this->vconn != NULL) {
166 fatal(0, "%s: connection dropped", this->name);
169 VLOG_WARN("%s: connection dropped, reconnecting", this->name);
170 vconn_close(this->vconn);
172 buffer_delete(this->rxbuf);
175 this->pollfd->revents = POLLIN | POLLOUT;
178 time_t now = time(0);
181 if (now >= this->backoff_deadline) {
185 if (this->backoff > 60) {
188 VLOG_WARN("%s: waiting %d seconds before reconnect\n",
189 this->name, (int) (this->backoff_deadline - now));
190 sleep(this->backoff_deadline - now);
193 retval = vconn_open(this->name, &this->vconn);
195 VLOG_WARN("%s: connected", this->name);
196 if (vconn_is_passive(this->vconn)) {
197 fatal(0, "%s: passive vconn not supported in control path",
200 this->backoff_deadline = now + this->backoff;
205 fatal(0, "%s: connection failed", this->name);
207 VLOG_WARN("%s: connection failed (%s)", this->name, strerror(errno));
208 this->backoff_deadline = time(0) + this->backoff;
213 parse_options(int argc, char *argv[])
215 static struct option long_options[] = {
216 {"unreliable", no_argument, 0, 'u'},
217 {"verbose", optional_argument, 0, 'v'},
218 {"help", no_argument, 0, 'h'},
219 {"version", no_argument, 0, 'V'},
222 char *short_options = long_options_to_short_options(long_options);
228 c = getopt_long(argc, argv, short_options, long_options, &indexptr);
242 printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]);
246 vlog_set_verbosity(optarg);
262 printf("%s: Secure Channel\n"
263 "usage: %s [OPTIONS] nl:DP_ID tcp:HOST:[PORT]\n"
264 "\nConnects to local datapath DP_ID via Netlink and \n"
265 "controller on HOST via TCP to PORT (default: %d).\n"
266 "\nNetworking options:\n"
267 " -u, --unreliable do not reconnect after connections drop\n"
269 " -v, --verbose set maximum verbosity level\n"
270 " -h, --help display this help message\n"
271 " -V, --version display version information\n",
272 program_name, program_name, OFP_TCP_PORT);