return 0;
fail:
/* let the upper layer know the connection failed */
- if (sc)
+ if (sc) {
sc->app_ops->wake(sc);
+ }
+ else if (conn_reverse_in_preconnect(conn)) {
+ struct listener *l = conn_active_reverse_listener(conn);
+
+ /* If mux init failed, consider connection on error.
+ * This is necessary to ensure connection is freed by
+ * proto-reverse-connect receiver task.
+ */
+ if (!conn->mux)
+ conn->flags |= CO_FL_ERROR;
+
+ /* If connection is interrupted without CO_FL_ERROR, receiver task won't free it. */
+ BUG_ON(!(conn->flags & CO_FL_ERROR));
+
+ task_wakeup(l->rx.reverse_connect.task, TASK_WOKEN_ANY);
+ }
return -1;
} else
return conn_complete_session(conn);
/* Receiver must reference a reverse connection as pending. */
BUG_ON(!l->rx.reverse_connect.pend_conn);
l->rx.reverse_connect.pend_conn = NULL;
+ l->rx.reverse_connect.task->expire = MS_TO_TICKS(now_ms + 1000);
+ task_queue(l->rx.reverse_connect.task);
}
conn_force_unsubscribe(conn);
struct connection *conn = l->rx.reverse_connect.pend_conn;
if (conn) {
- /* Spurrious receiver task wake up when pend_conn is not ready/on error. */
- BUG_ON(!(conn->flags & CO_FL_REVERSED));
- /* A connection is ready to be accepted. */
- listener_accept(l);
- l->rx.reverse_connect.task->expire = TICK_ETERNITY;
+ if (conn->flags & CO_FL_ERROR) {
+ conn_full_close(conn);
+ conn_free(conn);
+ l->rx.reverse_connect.pend_conn = NULL;
+
+ /* Retry on 1s on error. */
+ l->rx.reverse_connect.task->expire = MS_TO_TICKS(now_ms + 1000);
+ }
+ else {
+ /* Spurrious receiver task wake up when pend_conn is not ready/on error. */
+ BUG_ON(!(conn->flags & CO_FL_REVERSED));
+
+ /* A connection is ready to be accepted. */
+ listener_accept(l);
+ l->rx.reverse_connect.task->expire = TICK_ETERNITY;
+ }
}
else {
/* No pending reverse connection, prepare a new one. Store it in the