+static unsigned int
+timeout_VOID(const struct rconn *rc)
+{
+ return UINT_MAX;
+}
+
+static void
+run_VOID(struct rconn *rc)
+{
+ /* Nothing to do. */
+}
+
+static int
+reconnect(struct rconn *rc)
+{
+ int retval;
+
+ VLOG_WARN("%s: connecting...", rc->name);
+ rc->n_attempted_connections++;
+ retval = vconn_open(rc->name, OFP_VERSION, &rc->vconn);
+ if (!retval) {
+ rc->backoff_deadline = time_now() + rc->backoff;
+ state_transition(rc, S_CONNECTING);
+ } else {
+ VLOG_WARN("%s: connection failed (%s)", rc->name, strerror(retval));
+ rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */
+ disconnect(rc, 0);
+ }
+ return retval;
+}
+
+static unsigned int
+timeout_BACKOFF(const struct rconn *rc)
+{
+ return rc->backoff;
+}
+
+static void
+run_BACKOFF(struct rconn *rc)
+{
+ if (timed_out(rc)) {
+ reconnect(rc);
+ }
+}
+
+static unsigned int
+timeout_CONNECTING(const struct rconn *rc)
+{
+ return MAX(1, rc->backoff);
+}
+
+static void
+run_CONNECTING(struct rconn *rc)
+{
+ int retval = vconn_connect(rc->vconn);
+ if (!retval) {
+ VLOG_WARN("%s: connected", rc->name);
+ rc->n_successful_connections++;
+ state_transition(rc, S_ACTIVE);
+ rc->last_connected = rc->state_entered;
+ } else if (retval != EAGAIN) {
+ VLOG_WARN("%s: connection failed (%s)", rc->name, strerror(retval));
+ disconnect(rc, retval);
+ } else if (timed_out(rc)) {
+ VLOG_WARN("%s: connection timed out", rc->name);
+ rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */
+ disconnect(rc, 0);
+ }
+}
+
+static void
+do_tx_work(struct rconn *rc)
+{
+ if (!rc->txq.n) {
+ return;
+ }
+ while (rc->txq.n > 0) {
+ int error = try_send(rc);
+ if (error) {
+ break;
+ }
+ }
+ if (!rc->txq.n) {
+ poll_immediate_wake();
+ }
+}
+
+static unsigned int
+timeout_ACTIVE(const struct rconn *rc)
+{
+ if (rc->probe_interval) {
+ unsigned int base = MAX(rc->last_received, rc->state_entered);
+ unsigned int arg = base + rc->probe_interval - rc->state_entered;
+ return arg;
+ }
+ return UINT_MAX;
+}
+
+static void
+run_ACTIVE(struct rconn *rc)
+{
+ if (timed_out(rc)) {
+ unsigned int base = MAX(rc->last_received, rc->state_entered);
+ rconn_send(rc, make_echo_request(), NULL);
+ VLOG_DBG("%s: idle %u seconds, sending inactivity probe",
+ rc->name, (unsigned int) (time_now() - base));
+ state_transition(rc, S_IDLE);
+ return;
+ }
+
+ do_tx_work(rc);
+}
+
+static unsigned int
+timeout_IDLE(const struct rconn *rc)
+{
+ return rc->probe_interval;
+}
+
+static void
+run_IDLE(struct rconn *rc)
+{
+ if (timed_out(rc)) {
+ question_connectivity(rc);
+ VLOG_ERR("%s: no response to inactivity probe after %u "
+ "seconds, disconnecting",
+ rc->name, elapsed_in_this_state(rc));
+ disconnect(rc, 0);
+ } else {
+ do_tx_work(rc);
+ }
+}
+