static void qmux_ctrl_send(struct qc_stream_desc *, uint64_t data, uint64_t offset);
static void qmux_ctrl_room(struct qc_stream_desc *, uint64_t room);
+static int qcc_app_init(struct qcc *qcc);
+static void qcc_app_shutdown(struct qcc *qcc);
+
/* Returns true if pacing should be used for <conn> connection. */
static int qcc_is_pacing_active(const struct connection *conn)
{
++qcc->tx.paced_sent_ctr;
}
-/* Conduct I/O operations to finalize <qcc> app layer initialization. Note that
- * <qcc> app state may remain NULL even on success, if only a transient
- * blocking was encountered. Finalize operation can be retry later.
- *
- * Returns 0 on success else non-zero.
- */
-static int qcc_app_init(struct qcc *qcc)
-{
- int ret;
-
- TRACE_ENTER(QMUX_EV_QCC_SEND, qcc->conn);
-
- if (qcc->app_ops->finalize) {
- ret = qcc->app_ops->finalize(qcc->ctx);
- if (ret < 0) {
- TRACE_ERROR("app ops finalize error", QMUX_EV_QCC_NEW, qcc->conn);
- goto err;
- }
-
- if (ret) {
- TRACE_STATE("cannot finalize app ops yet", QMUX_EV_QCC_NEW, qcc->conn);
- goto again;
- }
- }
-
- qcc->app_st = QCC_APP_ST_INIT;
-
- again:
- TRACE_LEAVE(QMUX_EV_QCC_SEND, qcc->conn);
- return 0;
-
- err:
- TRACE_DEVEL("leaving on error", QMUX_EV_QCC_SEND, qcc->conn);
- return 1;
-}
-
/* Proceed to sending. Loop through all available streams for the <qcc>
* instance and try to send as much as possible.
*
TRACE_LEAVE(QMUX_EV_QCC_WAKE, qcc->conn);
}
-/* Execute application layer shutdown. If this operation is not defined, a
- * CONNECTION_CLOSE will be prepared as a fallback. This function is protected
- * against multiple invocation thanks to <qcc> application state context.
- */
-static void qcc_shutdown(struct qcc *qcc)
-{
- TRACE_ENTER(QMUX_EV_QCC_END, qcc->conn);
-
- if (qcc->flags & (QC_CF_ERR_CONN|QC_CF_ERRL)) {
- TRACE_DATA("connection on error", QMUX_EV_QCC_END, qcc->conn);
- goto out;
- }
-
- if (qcc->app_st >= QCC_APP_ST_SHUT)
- goto out;
-
- TRACE_STATE("perform graceful shutdown", QMUX_EV_QCC_END, qcc->conn);
- if (qcc->app_ops && qcc->app_ops->shutdown) {
- qcc->app_ops->shutdown(qcc->ctx);
- qcc_io_send(qcc);
- }
- else {
- qcc->err = quic_err_transport(QC_ERR_NO_ERROR);
- }
-
- if (conn_is_quic(qcc->conn)) {
- /* Register "no error" code at transport layer. Do not use
- * quic_set_connection_close() as retransmission may be performed to
- * finalized transfers. Do not overwrite quic-conn existing code if
- * already set.
- *
- * TODO implement a wrapper function for this in quic-conn module
- */
- if (!(qcc->conn->handle.qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE))
- qcc->conn->handle.qc->err = qcc->err;
- }
-
- /* A connection is not reusable if app layer is closed. */
- if (qcc->flags & QC_CF_IS_BACK)
- conn_delete_from_tree(qcc->conn, tid);
-
- out:
- qcc->app_st = QCC_APP_ST_SHUT;
- TRACE_LEAVE(QMUX_EV_QCC_END, qcc->conn);
-}
-
/* Loop through all qcs from <qcc> and wake their associated data layer if
* still active. Also report error on it if connection is already in error.
*/
}
if (close)
- qcc_shutdown(qcc);
+ qcc_app_shutdown(qcc);
}
/* Report error if set on stream endpoint layer. */
return 0;
}
+/* Conduct I/O operations to finalize <qcc> app layer initialization. Note that
+ * <qcc> app state may remain NULL even on success, if only a transient
+ * blocking was encountered. Finalize operation can be retry later.
+ *
+ * Returns 0 on success else non-zero.
+ */
+static int qcc_app_init(struct qcc *qcc)
+{
+ int ret;
+
+ TRACE_ENTER(QMUX_EV_QCC_SEND, qcc->conn);
+
+ if (qcc->app_ops->finalize) {
+ ret = qcc->app_ops->finalize(qcc->ctx);
+ if (ret < 0) {
+ TRACE_ERROR("app ops finalize error", QMUX_EV_QCC_NEW, qcc->conn);
+ goto err;
+ }
+
+ if (ret) {
+ TRACE_STATE("cannot finalize app ops yet", QMUX_EV_QCC_NEW, qcc->conn);
+ goto again;
+ }
+ }
+
+ qcc->app_st = QCC_APP_ST_INIT;
+
+ again:
+ TRACE_LEAVE(QMUX_EV_QCC_SEND, qcc->conn);
+ return 0;
+
+ err:
+ TRACE_DEVEL("leaving on error", QMUX_EV_QCC_SEND, qcc->conn);
+ return 1;
+}
+
+/* Execute application layer shutdown. If this operation is not defined, a
+ * CONNECTION_CLOSE will be prepared as a fallback. This function is protected
+ * against multiple invocation thanks to <qcc> application state context.
+ */
+static void qcc_app_shutdown(struct qcc *qcc)
+{
+ TRACE_ENTER(QMUX_EV_QCC_END, qcc->conn);
+
+ if (qcc->flags & (QC_CF_ERR_CONN|QC_CF_ERRL)) {
+ TRACE_DATA("connection on error", QMUX_EV_QCC_END, qcc->conn);
+ goto out;
+ }
+
+ if (qcc->app_st >= QCC_APP_ST_SHUT)
+ goto out;
+
+ TRACE_STATE("perform graceful shutdown", QMUX_EV_QCC_END, qcc->conn);
+ if (qcc->app_ops && qcc->app_ops->shutdown) {
+ qcc->app_ops->shutdown(qcc->ctx);
+ qcc_io_send(qcc);
+ }
+ else {
+ qcc->err = quic_err_transport(QC_ERR_NO_ERROR);
+ }
+
+ if (conn_is_quic(qcc->conn)) {
+ /* Register "no error" code at transport layer. Do not use
+ * quic_set_connection_close() as retransmission may be performed to
+ * finalized transfers. Do not overwrite quic-conn existing code if
+ * already set.
+ *
+ * TODO implement a wrapper function for this in quic-conn module
+ */
+ if (!(qcc->conn->handle.qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE))
+ qcc->conn->handle.qc->err = qcc->err;
+ }
+
+ /* A connection is not reusable if app layer is closed. */
+ if (qcc->flags & QC_CF_IS_BACK)
+ conn_delete_from_tree(qcc->conn, tid);
+
+ out:
+ qcc->app_st = QCC_APP_ST_SHUT;
+ TRACE_LEAVE(QMUX_EV_QCC_END, qcc->conn);
+}
+
/* Free all resources allocated for <qcc> connection. */
static void qcc_release(struct qcc *qcc)
{
return t;
release:
- qcc_shutdown(qcc);
+ qcc_app_shutdown(qcc);
qcc_release(qcc);
TRACE_LEAVE(QMUX_EV_QCC_WAKE);
*/
if (qcc_is_dead(qcc)) {
TRACE_STATE("releasing dead connection", QMUX_EV_QCC_WAKE, qcc->conn);
- qcc_shutdown(qcc);
+ qcc_app_shutdown(qcc);
qcc_release(qcc);
}
return;
release:
- qcc_shutdown(qcc);
+ qcc_app_shutdown(qcc);
qcc_release(qcc);
TRACE_LEAVE(QMUX_EV_STRM_END);
return;
return 0;
release:
- qcc_shutdown(qcc);
+ qcc_app_shutdown(qcc);
qcc_release(qcc);
TRACE_LEAVE(QMUX_EV_QCC_WAKE);
return 1;